套接字(Socket)
为了方便开发网络应用程序,美国伯克利大学在Unix上实现的一种应用程序访问网络的通信协议Socket,Socket的出现使程序员可以方便的访问TCP/IP(Transmission Control Protocol/Internet Protocol)即传输控制协议/网间协议
简单说:套接字允许应用程序将I/O插入到网络中,并与网络中的其他应用程序进行通信。网络套接字是IP地址与端口的组合。
TCP/IP
使用TCP/IP的套接字进行通信
- 服务器程序将一个套接字绑定到一个特定的端口,并通过此套接字等待和监听客户端端口的连接请求
- 客户端程序根据服务器程序所在的主机名和端口发出连接请求
- 使用ServerSocket和Socket实现服务器端和客户端的Socket通信
示意图
UPD
UPD是用户数据报协议,基于UPD的Socket编程是一种非链接的Socket通信,它提供的是无连接、不可靠的信息传送服务
- DatagramSocket:用来发送和接收数据包的套接字
- DatagramPacket:表示数据包
示意图:
TCP与UPD区别
- TCP面向连接,发送数据前要建立连接;UPD是无连接的,发送数据前不需要建立连接
- TCP传送的数据,无差错、不丢失、不重复,且按序到达;UPD尽最大努力交付,不保证可靠交付;(UPD传输效率高,但传输过程中质量没有很高的保证,适用于例如传图片、丢几个像素总没人看的出来)
- UPD有较好的实时性,效率比TCP高,适用于对高速传输和实时性较高的通信或广播通信
- 每一条TCP连接只能是点到点的,UPD支持一对一、一对多、多对一和多对多的交互通信
接下来我们通过几段代码来解释一下TCP与UDP的区别,尤其是第一点与第四点
- TCP:我们发现,TCP的传输是必须建立一个一对一的连接的
public class Server{//服务器端
public static void main(String[] args) {
try {
ServerSocket serverSocket = new ServerSocket(9999);//9999为服务器端的端口号,服务器启动了 并监听了9999
Socket socket = serverSocket.accept();//等待客户端连接到9999端口
InputStream inputStream = socket.getInputStream();//从客户端读取数据
OutputStream outputStream = new FileOutputStream("D:\\111.jpg");
byte[] car = new byte[1024];
int length = 0;
while((length=inputStream.read(car))!=-1) {
outputStream.write(car, 0, length);
}
outputStream.flush();
outputStream.close();
inputStream.close();
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public class Client{//客户端
public static void main(String[] args) {
try {
Socket socket = new Socket("127.0.0.1", 9999);//连接到ip地址的9999端口
OutputStream outputStream = socket.getOutputStream();//向服务器端写入数据
InputStream inputStream = new FileInputStream("D:\\timg.jpg");
byte[] car = new byte[1024];
int length = 0;
while((length=inputStream.read(car))!=-1) {
outputStream.write(car, 0, length);
}
outputStream.flush();
outputStream.close();
inputStream.close();
socket.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
- UPD:每个端口既是客户端也是服务器端,实现多对多交互通信
public class Server{
public static void main(String[] args) {
try {
DatagramSocket socket = new DatagramSocket(8888);//用来发送和接收数据包的套接字,虽然是服务器端,但是本端也可以充当客户端发送连接请求。故有多对多的交互通信
byte[] car = new byte[1024];
DatagramPacket packet = new DatagramPacket(car, 0, car.length);//定义一个数据包,用来接受1024个字节的数据
socket.receive(packet);//接收向本端口发送的数据包,放到car中
int length = packet.getLength();//获取数据长度
System.out.println(new String(car,0,length));//打印数据
} catch (Exception e) {
e.printStackTrace();
}
}
}
public class Client{
public static void main(String[] args) {
try {
DatagramSocket socket = new DatagramSocket(9999);//用来发送和接收数据包的套接字,虽然是客户端,但本端也可以是服务器端,该套接字可以接受到其他客户端的连接请求。故有多对多的交互通信
byte[] data = "来自客户端的问候".getBytes();
SocketAddress address = new InetSocketAddress("127.0.0.1", 8888);//客户端发送请求的地址
DatagramPacket packet = new DatagramPacket(data, data.length, address);//初始化一个数据包,包含数据和目标地址
socket.send(packet);//发送数据包
socket.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}