一、RFC
https://www.ietf.org/rfc/rfc768.txt
二、UDP协议概述
用户数据报协议(User Datagram Protocol)简称UDP协议,它是在IP的数据报服务上增加了端口和简单的差错检测来实现进程到进程之间的数据传输。
UDP协议有如下几个特点:
- 无连接。UDP是无连接的协议,数据传输之前不需要建立数据连接,也没有超时重传等机制,拥塞控制以及流量控制,但是传输速度快,灵活。
- 不可靠,尽最大努力交付。报文有可能存在重复,失序,丢失。
- 支持一对一,一对多,多对一,多对多的交互通信,组播以及广播功能。
- 面向报文。UDP是面向报文传输,对于应用层交下来的报文段不进行拆分合并,直接保留原有报文段的边界,然后添加UDP的首部就交付给网络层。
- 有边界。UDP存在保护消息边界,接收端一次只能接收发送端发出的一个数据包。客户端连续发送数据,即使服务端的这个函数的缓冲区足够大,也只会一次一次的接收,发送多少次接收多少次。
- 简单高效。由于UDP协议的简单性,它的开销相对较小,传输效率较高。适用于一些对传输速度要求较高、但对数据完整性要求不那么严格的应用场景。
三、UDP首部格式
UDP头部很简单,包括源端口,目的端口,UDP总长度,校验和,各占16位/2字节,共8字节。
- 源端口(Source port):长度16位,指定发送方所使用的端口号,若不需要对方回发消息,则可全置为0。
- 目的端口(Destination port):长度16位,指定接收方所使用的端口号。
- 长度(Length):长度16位,指定了UDP数据报的总长度,包含 UDP 报文头和 UDP 数据长度。因为 UDP 报文头长度是 8 个字节,所以这个值最小为 8。
- 校验和(Checksum):长度16位,用于UDP的差错检测,防止UDP报文出错,同时伪首部参与计算,避免UDP用户数据报传送到错误的目的地。UDP的首部,数据部分,伪首部都会参与检验和的计算,各字段是按照16比特为单位进行计算的,因此数据部分是要保证是16比特的倍数,不够用0填充。
UDP是一种全双工通信协议。 UDP协议首部中有一个16位的大长度. 也就是说一个UDP能传输的报文长度是64K(包含UDP首部)。如果我们需要传输的数据超过64K, 就需要在应用层手动的分包, 多次发送, 并在接收端手动拼装。
四、UDP缓冲区
UDP存在接收缓冲区,但不存在发送缓冲区。
UDP没有发送缓冲区,在调用发送数据函数时会直接将数据交给内核,由内核将数据传给网络层协议进行后续的传输动作。为什么UDP不需要发送缓冲区? 因为UDP不保证可靠性,它没有重传机制,当报文丢失时,UDP不需要重新发送,而TCP不同,他必须具备发送缓冲区,当报文丢失时,TCP必须保证重新发送,用户不会管,所以必须要具备发送缓冲区。
UDP具有接收缓冲区,但是这个接收缓冲区不能保证收到的UDP报文的顺序和发送UDP报的顺序一致,如果缓冲区满了再到达的UDP数据报就会被丢弃。
UDP套接口有发送缓冲区大小(SO_SNDBUF修改),不过它仅仅是写到套接口的UDP数据报的大小上限。如果一个应用程序写一个大于套接口发送缓冲区大小的数据报,内核将返回EMSGSIZE错误。既然UDP不可靠,它不必保存应用程序的数据拷贝,因此无需真正的发送缓冲区。
五、UDP协议的应用
UDP协议在网络通信中具有广泛的应用。以下是一些常见的应用场景:
-
实时音视频传输:由于UDP协议的低延迟和高效性,它广泛用于实时音视频传输,如音频会议、视频会议和流媒体服务等。在这些应用中,实时性比数据的可靠性更为重要。
-
DNS解析:UDP协议通常用于域名解析服务。当计算机向DNS服务器查询域名对应的IP地址时,通常使用UDP协议进行通信。由于DNS查询通常是简短的请求和响应,UDP协议适合这种快速而简单的通信。
-
游戏应用:在线游戏中,UDP协议被广泛应用于实时的游戏数据传输,如玩家位置、动作和声音等。UDP的低延迟和高效性能确保了玩家之间的即时互动和快速响应。
-
IoT设备通信:在物联网(IoT)中,大量的设备需要相互通信。由于UDP协议的简单性和高效性,它被广泛应用于IoT设备之间的数据传输,如传感器数据采集、智能家居控制等。
-
广播和多播:UDP协议支持广播和多播功能,可以将数据报一次性发送给多个目标设备。这在实时信息广播、视频直播和流媒体分发等场景中非常有用。
六、wireshark抓包实例
写了段python代码,发送10000个字节数据,抓包。
import socket # 导入socket模块
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # 创建UDP套接字
data = "*"*10000
s.sendto(data.encode(), ("10.10.10.xx", 8883)) # 发送数据
s.close() # 关闭套接字
第一个short, 0xcf11, 十进制53009, 表示源端口
第二个short, 0x22b3, 十进制8883, 表示目的端口,上面发送到的端口。
第三个short, 0x2718, 十进制10008, 表示UDP数据报的长度,扣除8字节头部,还能数据10000字节,也就是上面发送数据的长度。