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。
- 如果 校验和 计算结果为全 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 的基础上实现的一种可靠传输协议。