Sokcet
一. Socket套接字
1.1 什么是套接字
所谓套接字(Socket
),就是对网络中不同主机上的应用进程之间进行双向通信的端点的抽象。一个套接字就是网络上进程通信的一端,提供了应用层进程利用网络协议交换数据的机制,是支持TCP/IP
协议的路通信的基本操作单元
1.2 套接字主要类型
TCP
流套接字
流套接字用于提供面向连接、可靠的数据传输服务。该服务将保证数据能够实现无差错、无重复送,并按顺序接收。流套接字之所以能够实现可靠的数据服务,原因在于其使用了传输控制协议,即TCP
协议。即传输层TCP
通信满足如下条件:
- 有连接可靠传输
- 面向字节流,即可以利用
IO
流分开进行多次收发 - 有接受的缓冲区和传输缓冲区,没有传输大小限制
UDP
数据报套接字
数据报套接字提供一种无连接的服务。该服务并不能保证数据传输的可靠性,数据有可能在传输过程中丢失或出现数据重复,且无法保证顺序地接收到数据。数据报套接字使用UDP
协议进行数据的传输。由于数据报套接字不能保证数据传输的可靠性,对于有可能出现的数据丢失情况,需要在程序中做相应的处理。即传输层UDP
通信满足如下条件:
- 无连接不可靠传输
- 面向数据报,即发送的内容必须一次性收发
- 有接受的缓冲区,但没有发送的缓冲区,一次性最多传输
64k
大小
原始套接字
原始套接字与标准套接字(标准套接字指的是前面介绍的流套接字和数据报套接字)的区别在于:原始套接字可以读写内核没有处理的IP数据包,而流套接字只能读取TCP
协议的数据,数据报套接字只能读取UDP
协议的数据。因此,如果要访问其他协议发送的数据必须使用原始套接。
二. UDP常见API
2.1 DatagramSocket
DatagramSocket
用来构造传输UDP
协议的类,表格介绍如何构造类对象
构造方法 | 含义 |
---|---|
DatagramSocket(int port) | 创建一个UDP 数据报套接字Socket ,绑定到指定的端口 |
表格介绍DatagramSocket
常用的传输和接受数据包方法
方法 | 含义 |
---|---|
void receive(DatagramPacket p) | 套接字接收数据报 |
void send(DatagramPacket p) | 套接字发送数据报包 |
void close() | 关闭套接字 |
2.2 DatagramPacket
DatagramPacket
用来构造传输数据包的类,表格介绍如何构造类对象
构造方法 | 含义 |
---|---|
DatagramPacket(byte[] buffer, int length) | 构造数据包接受数据,parm1:接受的内容,parm2:指定接受的长度 |
DatagramPacket(byte[] buffer, int offset, int length,SocketAddress address) | 构造数据包发送数据,parm1:发送内容,parm2:从字符组下标哪里开始发送,parm3:发送的长度、parm4:封装目的IP 和端口对象 |
表格介绍DatagramPacket
常用的方法
方法 | 含义 |
---|---|
InetAddress getAddress() | 从接收的数据报中,获取发送端主机IP 地址;或从发送的数据报中,获取接收端主机IP 地址 |
int getPort() | 从接收的数据报中,获取发送端主机的端口号;或从发送的数据报中,获取接收端主机端口号 |
byte[] getData() | 获取数据报中的数据 |
2.3 SocketAddress
在上述DatagramPacket
对象发送数据包时,需要构造SocketAddress
来封装IP
和端口,我们常使用SocketAddress
的子类InetSocketAddress
来构建对象
构造方法 | 含义 |
---|---|
InetSocketAddress(InetAddress address, int port) | 创建一个Socket 地址,包含IP 地址和端口号 |
三. C/S结构测试
3.1 TCP通信
TCP
网络协议通信可查看这篇文章:
利用TCP网络编程实现客户端和服务端简单交互
3.2 UDP通信
下面讲解如何利用Socket实现C/S结构的UDP协议通信,如下图为传输过程
服务端
Server
//构建UDP协议的服务端public class UDPServer {//构建套接字DatagramSocket socket;//构建协议对象(参数表示服务器端口号)public UDPServer(int serverPort) throws SocketException {socket = new DatagramSocket(serverPort);}//开启服务器进行监听public void startListening() throws IOException {System.out.println("===============服务器开启监听===================");Scanner scanner = new Scanner(System.in);//用来回复while (true){//1.构建数据包用来接受数据DatagramPacket receivePacket = new DatagramPacket(new byte[1024], 1024);//2.等待接受数据(没有返回值,但是已经接收到了数据)socket.receive(receivePacket);//3.将接受的数据取出String receiveData = new String(receivePacket.getData(),0,receivePacket.getLength());//如果客户端发送来ex或exit则退出if ("ex".equals(receiveData) || "exit".equals(receiveData)){System.out.println("===============服务器退出===================");break;}//4.根据请求进行回复System.out.println("收到消息:{"+receiveData+"}");System.out.println("请输入想要回复的信息:");String answer = scanner.nextLine();byte[] answerBytes = answer.getBytes();//5.将回复封装为数据包发送回客户端//注意:这里是根据接受的数据包来获取发送方的ip和端口DatagramPacket answerPacket = new DatagramPacket(answerBytes, 0, answerBytes.length, receivePacket.getSocketAddress());socket.send(answerPacket);}}public static void main(String[] args) throws IOException {UDPServer udpServer = new UDPServer(8899);udpServer.startListening();}}
客户端
Client
//构建UDP协议的客户端public class UDPClient {//服务器端口号int serverPort;//服务器ipString serverIp;//构建套接字DatagramSocket socket;//构建协议对象(参数表示服务器端口号和服务器ip地址)public UDPClient(int serverPort, String serverIp) throws SocketException {this.serverIp = serverIp;this.serverPort = serverPort;this.socket = new DatagramSocket();}public void startSend() throws IOException {System.out.println("===============客户端开启接受===================");//1.获取输入Scanner scanner = new Scanner(System.in);while (true){System.out.println("请输入想要发送的信息:");String request = scanner.nextLine();byte[] requestBytes = request.getBytes();//2.构建数据包//InetAddress.getByName()表示根据服务器主机名称解析ip地址DatagramPacket requestPacket = new DatagramPacket(requestBytes, 0, requestBytes.length, InetAddress.getByName(serverIp), serverPort);//3.发送数据包socket.send(requestPacket);//设定退出if ("ex".equals(request) || "exit".equals(request)){System.out.println("===============客户端退出===================");break;}//4.构建数据包用来获取响应DatagramPacket receivePacket = new DatagramPacket(new byte[1024], 1024);socket.receive(receivePacket);//5.将获取的数据取出String receiveData = new String(receivePacket.getData(),0,receivePacket.getLength());System.out.println("收到消息:{"+receiveData+"}");}}public static void main(String[] args) throws IOException {UDPClient udpClient = new UDPClient(8899, "192.168.31.104");udpClient.startSend();}}
服务器端运行在192.168.31.104
上,利用如下代码开启监听:
java -cp NetworkSocket-1.0-SNAPSHOT.jar com.nuaa.mySocket.server.UDPServer
客户端运行在本地,通信对话如下