1、UDP协议根本
1. UDP是什么?
UDP(User Datagram Protocol,用户数据报协议)是传输层的焦点协议之一,与TCP并列。它的主要特点是:
- 无毗连:通讯前不须要创建毗连(知道对端的IP和端标语就直接进行传输,不须要创建毗连)
- 不可靠:不包管数据包的次序、完备性或可达性(没有确认机制,没有重传机制;假如由于网络故障该段无法发到对方,UDP协议层也不会给应用层返回任何错误信息)
- 巨细受限:⼀次最多传输64k(UDP协议首部中有⼀个16位的最大长度.也就是说⼀个UDP能传输的数据最大长度是 64K(包罗UDP首部))
- 轻量级:头部开销小(仅8字节)
- 高效:没有TCP的握手、确认和重传机制
2. UDP报文布局
UDP数据包(称为数据报)由头部和数据部分构成:
- 源端标语(2字节):发送方端口
- 目的端标语(2字节):吸收方端口
- 数据报长度(2字节):头部+数据的长度
- 校验和(2字节):错误检测(可选)假如校验和堕落则直接抛弃
2、UDP的焦点特性
1. 无毗连通讯:UDP不须要预先创建毗连,直接发送数据报。这雷同于寄信,不须要确认收件人是否在家。
2. 不可靠传输:UDP不提供:数据包确认机制、丢失重传机制、数据包排序功能
3.面向数据报:每个UDP数据报都是独立的,这与TCP的字节流模式差别
4.支持广播和多播:UDP可以向多个主机同时发送数据:
- 单播 :一对一
- 广播 :一对全部
- 多播 :一对一组
3、基于UDP的应用层协议
- NFS:网络文件系统
- TFTP:简朴文件传输协议
- DHCP:动态主机设置协议
- BOOTP:启动协议(用于无盘装备启动)
- DNS:域名剖析协议
当然,也包罗我们自己写UDP步调时自界说的应用层协议。
4、Java中的UDP编程
主要使用了两个类 :
1、DatagramSocket :用于发送和吸收数据报的套接字
// 创建UDP套接字(绑定随机端口)
DatagramSocket socket = new DatagramSocket();
// 创建绑定特定端口的套接字
DatagramSocket serverSocket = new DatagramSocket(8080);
2、DatagramPacket :体现UDP数据报的容器
// 创建吸收数据包
byte[] buffer = new byte[1024];
DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
// 创建发送数据包
String message = "Hello UDP";
byte[] data = message.getBytes();
DatagramPacket sendPacket = new DatagramPacket(
data,
data.length,
InetAddress.getByName("localhost"),
8080
);
5、完备Java UDP示例
1.Echoserver:UDP服务器,吸收客户端消息并原样返回
- package Network.UDP;
- import java.io.IOException;
- import java.net.DatagramPacket;
- import java.net.DatagramSocket;
- import java.net.SocketException;
- public class Echoserver {
- //创建一个socket对象
- private DatagramSocket socket;
- //构造方法,初始化socket对象
- public Echoserver(int port) throws SocketException {
- socket = new DatagramSocket(port);
- }
- //启动服务器,完成主要的业务逻辑
- public void start() throws IOException {
- System.out.println("服务器启动!");
- while(true) {
- //1.接收客户端的请求并解析
- //1)创建一个字节数组(DatagramPacket 对象),用于存储接收到的数据
- DatagramPacket reqPacket = new DatagramPacket(new byte[4096],4096);
- //2)通过receive读取网卡的数据,如果网卡没有收到数据,就会阻塞等待
- socket.receive(reqPacket);
- //3)把DATagramPacket中的数据解析成字符串,只需要从DatagramPacket取到有效的树即可
- String request = new String(reqPacket.getData(),0,reqPacket.getLength());
- //2.根据请求计算响应
- String response = process(request);
- //3.把响应写回客户端
- //1)把响应字符串转成字节数组,并封装成DatagramPacket对象
- DatagramPacket resPacket = new DatagramPacket(response.getBytes(),response.getBytes().length,
- reqPacket.getSocketAddress());
- //2)通过socket把DatagramPacket对象发送出去 (把DatagramPacket写回到客户端)
- socket.send(resPacket);
- //4.打印日志
 - System.out.printf("[%s:%d] req: %s,resp: %s\n",
- reqPacket.getAddress(),reqPacket.getPort(),request,response);
- }
- }
- //由于是“回显服务器”,所以响应和请求是一样的,直接返回请求即可
- public String process(String request) {
- return request;
- }
- public static void main(String[] args) throws IOException {
- Echoserver server = new Echoserver(9090);
- server.start(); //回显服务器完成
- }
- }
复制代码 代码具体剖析:
①创建 EchoServer 服务端的类,界说成员变量
- DatagramSocket:UDP通讯的焦点类,用于发送和吸收数据报
- 封装在类中作为成员变量,整个生命周期内有用
②构造方法
- 创建绑定到指定端口的 DatagramSocket(可能会抛出异常,如:该端口已被占用)
- port 是服务器自身绑定的监听端标语,等待客户端发送数据,客户端须要知道服务器的这个端标语才气向其发送消息。
- 客户端通过该端口找到服务器,而客户端的端口由系统动态分配。
- 这种计划体现了 UDP 无毗连的特性,服务器只需关注自身绑定端口即可吸收全部客户端消息。
③焦点业务逻辑(start方法)
- while 无穷循环吸收来自客户端的数据,这里可以根据自己的需求更改吸收次数
- 创建缓冲区:分配一个4096字节(字节巨细自行界说不溢出就行)的空数组,存储吸收到的数据
- 壅闭等待数据报到达(数据此时已存入 reqPacket 的字节数组中)假如 reqPacket 没有吸收到客户端发来的数据这里会壅闭等待
- 声明 String 范例的 request 变量,将 reqPacket 中的数据剖析为字符串
- getData() :获取字节数组(可能包罗多余的空字节)
- getLength() :获取实际有用数据长度(制止剖析无效字节)
在网络编程中,将相应(response)转成字节数组(byte[])再发送是须要的步调,这与盘算机底层的数据传输机制和网络协议的特性密切干系。
- process() :返回相应后的数据,由于整段代码实现的是 Echo(回显) 服务器代码,相应内容=哀求内容,所以方法中直接返回哀求即可
- soclet.send() :将数据发送回客户端
附上发送回客户端的终端代码
- 打印日志
:打印客户端信息和通讯内容
④主方法
- new Echoserver(9090) :调用构造函数,创建绑定到 9090 端口的 DatagramSocket(UDP套接字)
- server.start() :启动服务器循环,等待客户端数据报
2.EchoClient:UDP客户端,发送消息并显示服务器返回的相应
- package Network.UDP;
- import java.io.IOException;
- import java.net.DatagramPacket;
- import java.net.DatagramSocket;
- import java.net.InetAddress;
- import java.util.Scanner;
- public class EchoClient {
- private DatagramSocket socket = null;
- private String serverIp;
- private int serverPort;
- public EchoClient(String serverIp, int serverPort) throws IOException {
- socket = new DatagramSocket();
- this.serverIp = serverIp;
- this.serverPort = serverPort;
- }
- //启动客户端,发送数据,接收数据,关闭连接
- public void start() throws IOException {
- Scanner scanner = new Scanner(System.in);
- System.out.println("客户端启动!");
- while(true) {
- //1.从控制台读取要发送的数据内容(用字符串表示)
- System.out.print(">");
- String request = scanner.nextLine();
- //2.构造成UDP请求,并发送.不光要填内容,还要填服务器的地址和端口号
- DatagramPacket reqPacket = new DatagramPacket(request.getBytes(),request.getBytes().length,
- InetAddress.getByName(serverIp),serverPort);
- socket.send(reqPacket);
- //3.接收服务器响应的数据
- DatagramPacket resPacket = new DatagramPacket(new byte[4096], 4096);
- socket.receive(resPacket);
- String response = new String(resPacket.getData(),0,resPacket.getLength());
- //4.把响应的数据解析并打印
- System.out.println(response);
- }
- }
- public static void main(String[] args) throws IOException {
- EchoClient echoclient = new EchoClient("127.0.0.1",9090);
- echoclient.start();
- }
- }
复制代码 具体代码剖析:
①创建 EchoClient 客户端的类,界说成员变量
- socket :客户端UDP套接字
- serverIp/serverPort :服务器地点信息
②构造方法
- DatagramSocket ( ) 为客户端随机分配一个端标语
- 保存服务器地点信息
③焦点业务逻辑(start方法)
- request 用户输入要发送的数据
- reqPacket 封装要发送的数据
- request.getBytes() :将用户输入的字符串转换为字节数组
- request.getBytes().length :获取字节数组的长度,体现要发送的数据巨细
- InetAddress.getByName(serverIp) :通过服务器的IP地点获取对应的 InetAddress 对象,体现数据要发送到的目的地点
- serverPort :服务器的端标语,体现数据要发送到的端口
- socket.send() :调用 send 方法将数据报发送到指定的目的地点和端口
- resPacket() :吸收服务器发回的相应数据,socket.receive() 是一个壅闭操纵,直到吸收到数据才会继续实行
- response :提取相应内容,将吸收到的字节数据转换为字符串
④主方法
- 创建客户端实例,毗连当地服务器的9090端口
- start 启动客户端
6、UDP编程注意事项
1.数据报巨细限制
- UDP数据报最大长度理论为65535字节
- 实际受MTU限制(通常1500字节)
- 发起保持数据报在1472字节以内(IPv4)
2.数据界限标题
- 每个 receive() 调用吸收一个完备的数据报
- 不会出现TCP的“粘包”标题
3.错误处置惩罚
4.安全性考虑
- UDP易受DDoS攻击
- 应考虑实现应用层的验证机制
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
|