传输层网络协议
1. UDP协议
1.1 特点
- 面向数据报(DatagramSocket)
- 数据报大小限制为64k
- 全双工
- 不可靠传输
- 有接收缓冲区,无发送缓冲区
UDP的特点,我理解起来就是工人组成的**“人工传送带”**:
- 面向数据报(DatagramSocket):工人们能够知道的只有装货物的袋子,并不知道里面装的什么内容,这个麻袋上印着各种信息,包括送往哪里,送给谁,谁发送的等能够确保货物定位到人的信息。
- **数据报大小限制为64k:**一个麻袋装的货物是有容量限制的。
- **全双工:**这条“人工传送带”可以将货物正向运输,也可以逆向运输。
- **不可靠传输:**工人只管将一袋一袋的货物运到目的地,但是不管袋子中的货物是什么,也不管发货地与收货地的老板沟通好了没有,工人们收到的指令只是将货物运到从起始地运到目的地。
- **有接收缓冲区,无发送缓冲区:**工人们将货物运走的过程中,起始地并没有设置缓冲区,工人可以直接搬走,但是目的地有缓冲区,即目的地是有放置一部分货物的地方的。
1.2 模型
以图示进行说明:
从上图中也可以看出来:
- UDP并没有所谓的建立连接的过程,只是需要发送数据的时候就去调用socket.send()进行发送。
- 一共经历了两次send()和receive()操作
1.3 代码
完成的是一个"回显"的UDP代码。
1) 客户端代码
package UDP;
import java.io.IOException;
import java.net.*;
public class Server {
private DatagramSocket serverSocket = null;
public Server(int port) throws SocketException {
serverSocket = new DatagramSocket(port);// 服务器端需要指定端口
}
public void start() throws IOException {
while (true) {
System.out.println("等待客户端连接...");
// 1. 构造数据报
byte[] bytes = new byte[1024];// UDP接收信息不可超出 64*1024b
DatagramPacket reqPacket = new DatagramPacket(bytes, bytes.length);
// 2. 接收数据报并解析
serverSocket.receive(reqPacket);// 输出型参数
String req = new String(bytes, 0, reqPacket.getLength());
System.out.println("收到服务器请求: " + req);
// 3. 构造响应并发送数据报
String resp = process(req);
DatagramPacket respPacket = new DatagramPacket(resp.getBytes(), 0, resp.getBytes().length, reqPacket.getSocketAddress());
serverSocket.send(respPacket);
System.out.println("已反馈: " + resp);
}
}
private String process(String req) {
return req;
}
public static void main(String[] args) throws IOException {
Server server = new Server(2024);
server.start();
}
}
2) 服务端代码
package UDP;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;
import java.net.SocketException;
import java.util.Scanner;
public class Client {
private DatagramSocket clientSocket = null;
public Client() throws SocketException {
clientSocket = new DatagramSocket();// 客户端是随机端口
}
public void start() throws IOException {
while (true) {
System.out.print("->");
// 1. 构造请求并发送
Scanner scanner = new Scanner(System.in);
String req = scanner.next();
DatagramPacket reqSocket = new DatagramPacket(req.getBytes(), 0, req.getBytes().length, new InetSocketAddress("127.0.0.1", 2024));
clientSocket.send(reqSocket);
System.out.println("已发送: " + req);
// 2. 接收服务器请求
byte[] bytes = new byte[1024];
DatagramPacket respPacket = new DatagramPacket(bytes, 0, bytes.length);
clientSocket.receive(respPacket);
String resp = new String(respPacket.getData(), 0, respPacket.getLength());
System.out.println("收到服务器反馈: " + resp);
}
}
public static void main(String[] args) throws IOException {
Client client = new Client();
client.start();
}
}
运行结果:
3) 注意事项:
-
发送的时候必须在DatagramPacket中指定目的地,即:
-
客户端:
new InetSocketAddress("127.0.0.1", 2024)
客户端是因为是本次通信中需要主动建立连接的一方,所以由客户端进行提出连接到哪台服务器和哪个端口对其进行提供服务。
-
服务端:
reqPacket.getSocketAddress()
服务端提供服务,在向客户端反馈响应的时候,这个地址应遵循:“谁发送过来,就返回到谁那里”。
-
-
接收数据报的时候并不需要指定任何地址或者端口。
-
UDP接收信息不可超出 64*1024b
-
数据报中包含了一切所需要的信息,Datagram’Socket只是辅助完成发送和接收的操作。