UDP
UDP 数据报
UDP(User Datagram Protocol)首部的长度固定为 8 个字节(64 位),不论 UDP 携带的数据量大小如何,其首部都保持不变。UDP 首部的各个字段如下:
- 源端口(Source Port):占用 2 个字节(16 位),用于标识发送方应用程序的端口号。
- 目标端口(Destination Port):占用 2 个字节(16 位),用于标识接收方应用程序的端口号。
- 长度(Length):占用 2 个字节(16 位),指示 UDP 数据报的总长度,包括首部和数据。因此,最小长度为 8 字节。
- 校验和(Checksum):占用 2 个字节(16 位),用于检测 UDP 数据报在传输过程中是否受到损坏。
当传输层从 IP 层收到 UDP 数据报时,就根据首部中的目的端口,把 UDP 数据报通过 相应的端口,上交最后的终点一一应用进程,如下图所示:
若接收方 UDP 发现收到的报文中的目的端口号不正确(即不存在对应于端口号的应用进程),则就丢弃该报文,并由 ICMP 发送“端口不可达”差错报文给发送方。
UDP 校验
UDP 的校验和(checksum)用于检测数据在传输过程中是否发生错误。它覆盖 UDP 头部、数据部分以及部分 IP 头部信息(伪头部),确保数据的完整性。
这种简单的差错检验方法的校错能力并不强,但它的好处是简单、处理速度快。
发送端
UDP 的发送方需要计算 checksum 字段的值,并且填充进 UDP 首部相应字段中。 发送方计算 checksum 包含构造伪首部、组合校验数据、计算 16 位和、按位取反四个步骤。
- 构造伪头部
为了确保源和目的地址的正确性,UDP 校验和包含一个伪头部(不实际传输,仅用于计算)。伪头部包括:
- 源 IP 地址(32 位,IPv4)
- 目的 IP 地址(32 位,IPv4)
- 协议字段(8 位,UDP 为 17)
- UDP 长度(16 位,UDP 头部+数据的总字节数)
- 填充位(8 位,通常为 0,确保伪头部长度为 12 字节)
- 组合校验数据
将以下内容按 16 位分组:
- 伪头部
- UDP 头部(包括源端口、目的端口、长度、校验和字段,校验和字段初始置 0)
- 数据部分(若数据长度为奇数字节,末尾补 0 凑成 16 位)
- 计算 16 位和
- 将所有 16 位数逐一相加,记录进位。
- 如果有进位(和超过 16 位),将进位加到低 16 位(称为 回卷)。
- 例如:若两个 16 位数相加得
1 0000 0000 0000 0001
,则取低 16 位0000 0000 0000 0001
并加 1,得0000 0000 0000 0010
。
- 按位取反
- 对最终的 16 位和按位取反(0 变 1,1 变 0),得到校验和。
- 将此校验和填入 UDP 头部的校验和字段。
- 特殊情况
- 如果校验和计算结果为全 0,则发送
1111 1111 1111 1111
(全 1),以避免与“校验和禁用”(全 0)混淆。 - UDP 校验和是可选的,若不使用,校验和字段置为全 0。
注意
检验时,若 UDP 数据报部分的长度不是偶数个字节,则需填入一个全 0 字节进行填充
若 UDP 检验和检验出 UDP 数据报是错误的,则可以丢弃,也可以交付给上层,但是需要附上错误报告,即告诉上层这是错误的数据报。
计算 16 位和的过程中,如果有进位,不要忘记 “回卷”。
接收端
接收端通过以下步骤验证数据完整性:
- 提取校验数据:接收端同样构造伪头部(使用接收到的 IP 头部信息),并提取伪首部、UDP 首部(包括接收到的校验和)、数据部分。
- 计算 16 位和:将所有 16 位数(包括接收到的校验和)相加,记录并回卷进位。如果数据无误,和的结果应为
1111 1111 1111 1111
(全 1)。 - 验证结果
- 如果最终和为全 1,说明数据正确,无错误。
- 如果和不为全 1,说明数据在传输中发生错误,接收端通常丢弃该数据报(UDP 不负责重传)。
- 处理特殊情况
- 如果接收到校验和为全 0,表示发送端禁用了校验和,接收端可直接接受数据(不校验)。
- 如果校验和为全 1,需按上述步骤验证。
实例
假设我们要发送一个 UDP 数据报,相关信息如下:
- 源 IP 地址:192.168.1.1(二进制:11000000 10101000 00000001 00000001)
- 目的 IP 地址:192.168.1.2(二进制:11000000 10101000 00000001 00000010)
- 源端口:1024(二进制:00000100 00000000)
- 目的端口:2048(二进制:00001000 00000000)
- 数据:0x48656C(3 字节,“Hel”)
则得到 16 位组合数据和校验和计算过程如下所示:
计算得到的校验和为:00111011 00011111(十六进制:0x3B1F)。
当接收端接收到 UDP 数据报是,接收端将所有 16 位数(包括校验和 00111011 00011111
)相加:
重复上述加法,最后一步加上校验和:11000100 11100000
+ 00111011 00011111
= 11111111 11111111
(全 1)
UDP 特点
- 无连接性:UDP 是一种无连接的协议,这意味着在发送数据之前,发送方和接收方之间不建立连接。每个 UDP 数据报都是独立的,没有先后顺序的要求。
- 轻量级:UDP 非常轻量级,因为它不涉及连接建立和维护,也不包括复杂的拥塞控制算法。这使得 UDP 非常适用于低延迟和高吞吐量的应用。
- 无序性:UDP 数据报在传输过程中不保持顺序。这意味着发送方发送的多个 UDP 数据报可能以不同的顺序到达接收方,并且接收方需要自行处理数据的顺序问题。
- 不可靠性:UDP 不提供可靠性。它不保证数据的传输成功,也不负责重新发送丢失的数据。如果数据在传输过程中丢失或损坏,接收方将不会收到任何通知,并且需要根据应用程序的要求自行处理这些问题。
- 广播和多播:UDP 支持广播和多播,允许一个 UDP 数据报同时发送到多个接收方。
应用场景
UDP 常用于 一次性传输较少数据 的网络应用,如 DNS、SNMP 等,因为对于这些应用,若采用 TCP,则将为连接创建、维护和拆除带来不小的开销。
UDP 也常用于 对延迟敏感 多媒体应用(如 电子游戏、实时视频会议、流媒体等),显然,可靠数据传输对这些应用来说并不是最重要的, 但 TCP 的拥塞控制会导致数据出现较大的延迟,这是它们不可容忍的。
UDP 不保证可靠交付,但这并不意味着应用对数据的要求是不可靠的,所有维护可靠性的工作可由用户在应用层来完成。应用开发者可根据应用的需求来灵活设计自己的可靠性机制。
比如 HTTP3 中使用的 QUIC 就是在 UDP 的基础上实现的一种可靠传输协议。