UDP
需要关注下 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)混淆。 - 在 IPv4 中 UDP 校验和可选,若不使用就把字段置为全 0;在 IPv6 中 UDP 校验和通常是必需的,不能把全 0 当作一般的“禁用校验”。
- 如果 校验和 计算结果为全 0,则发送
注意
检验时,若 UDP 数据报部分的长度不是偶数个字节,则需填入一个全 0 字节进行填充
若 UDP 校验和检验失败,接收端应丢弃该数据报;UDP 不负责重传。不要把损坏数据当作普通有效报文交付给应用。
计算 16 位和的过程中,如果有进位,不要忘记“回卷”。
接收端
接收端通过以下步骤验证数据完整性:
- 提取校验数据:接收端同样构造 伪头部(使用接收到的 IP 头部信息),并提取 伪首部、UDP 首部(包括接收到的校验和)、数据部分。
- 计算 16 位和:将所有 16 位数(包括接收到的校验和)相加,记录并回卷进位。如果数据无误,和的结果应为
1111 1111 1111 1111(全 1)。 - 验证结果
- 如果最终反码和为全 1,表示 校验通过、未检测到差错;校验和不能证明绝对无错。
- 如果和不为全 1,说明数据在传输中发生错误,接收端通常丢弃该数据报(UDP 不负责重传)。
- 处理特殊情况
- IPv4 UDP 若收到校验和全 0,表示发送端禁用了校验;IPv6 UDP 通常不允许这样解释。
- 如果校验和为全 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 位组合数据和校验和计算过程如下所示:
本例 UDP 长度为 B,即 0x000B。把所有 16 位字做反码加法后,回卷和为 0x43E1,按位取反得到校验和。写入首部的值可记为 。
原文给出的 0x3B1F 与所列 IP、端口、长度和数据不一致;按这些字段重新核算应为 0xBC1E。接收端把所有 16 位字(包括校验和 0xBC1E)相加并回卷,结果应为 0xFFFF(全 1)。
下面的交互按 16 位字逐项加入累加器,显示每次进位回卷和最终取反;静态排列图保留作手算底稿。
UDP 校验和的 16 位回卷累加
使用 192.168.1.1:1024 到 192.168.1.2:2048、数据 Hel 的原例,逐组累加伪首部、UDP 首部和数据,得到回卷和 0x43E1 与校验和 0xBC1E。
当前查看:排列伪首部。源地址拆为 C0A8、0101,目的地址拆为 C0A8、0102,再加入 0011(UDP 协议号 17)和 000B(长度 11 B)。
UDP 特点
- 无连接性:UDP 是一种 无连接 的协议,这意味着在发送数据之前,发送方和接收方之间不建立连接。每个 UDP 数据报都是独立的,没有先后顺序的要求。
- 轻量级:UDP 非常 轻量级,因为它不涉及连接建立和维护,也不包括复杂的拥塞控制算法。这使得 UDP 非常适用于 低延迟 和 高吞吐量 的应用。
- 无序性:UDP 数据报在传输过程中 不保持顺序。这意味着发送方发送的多个 UDP 数据报可能以不同的顺序到达接收方,并且接收方需要自行处理数据的顺序问题。
- 不可靠性:UDP 不提供可靠性。它不保证数据的传输成功,也不负责重新发送丢失的数据。如果数据在传输过程中丢失或损坏,接收方将不会收到任何通知,并且需要根据应用程序的要求自行处理这些问题。
- 广播和多播:UDP 支持 广播和多播,允许一个 UDP 数据报同时发送到多个接收方。
应用场景
UDP 常用于 一次性传输较少数据 的网络应用,如 DNS、SNMP 等,因为对于这些应用,若采用 TCP,则将为连接创建、维护和拆除带来不小的开销。
UDP 也常用于 对延迟敏感 的多媒体应用(如 电子游戏、实时视频会议、流媒体 等),显然,可靠数据传输对这些应用来说并不是最重要的,但 TCP 的拥塞控制会导致数据出现较大的延迟,这是它们不可容忍的。
UDP 不保证可靠交付,但这并不意味着应用对数据的要求是不可靠的,所有维护可靠性的工作可由用户在 应用层 来完成。应用开发者可根据应用的需求来灵活设计自己的可靠性机制。
例如 HTTP/3 使用的 QUIC 就构建在 UDP 之上,并在用户空间实现可靠传输、拥塞控制、加密和多路复用;这说明“UDP 不保证可靠”不等于“基于 UDP 的应用一定不可靠”。