Appearance
UDP 协议
2026 大纲 五(二)1 UDP 数据报 与 五(二)2 UDP 校验。传输层为什么存在、端口为什么取代进程标识符、无连接与面向连接的本质差别写在 TCP 与 UDP 对比。
一、只加两件事,为什么还值得设一个协议
IP 把分组交到目的主机的网络层就算完成任务,而真正在通信的是主机里的应用进程;IP 首部里也有检验和,但它只检验首部、不检验数据部分。
UDP 补的正是这两处缺口,也只补这两处:在 IP 数据报服务之上只增加复用分用与差错检测,其余可靠性机制全部拿掉。
一份数据要到达进程,得过两道分用关:先按 IP 首部的协议字段挑协议(UDP = 17,TCP = 6),再按目的端口挑进程。
复用分用是刚需(少了它 IP 数据没法交付进程),可靠性机制则是可选的。把可选的全部拿掉,剩下这个 8 字节的最小传输层——它的设计意图是给应用留一条"我自己来"的通道,而不是"TCP 的残缺版"。
交互可视化
二、五个特点全部由"首部只有 8 字节"推出
| 特点 | 它买到了什么 | 它的代价 |
|---|---|---|
| 无连接 | 省掉一次握手的 RTT 与两端的连接状态表 | 收方无法预分配缓存,也不知道"对方还在不在" |
| 不可靠 | 不用维护重传队列与计时器 | 丢了就是丢了,失序不纠正 |
| 面向报文 | 边界天然保留,一次发对应一次收 | "报文该多大"被推给应用 |
| 无拥塞控制 | 发送速率恒定,实时性有保障 | 拥塞时不让路,挤压自觉降速的 TCP |
| 支持一对多、多对多 | 能做广播与多播 | —(TCP 做不到,连接天生只有两个端点) |
| 首部只有 8 字节 | 小报文开销远低于 TCP 的 20 字节 | 放不下序号、确认号、窗口 |
最后一行是因,前面几行是果。 首部里没有地方放序号,就无法确认、无法重传、无法排序、无法做窗口——"不可靠""无拥塞控制"是首部尺寸的必然推论。
被推给应用的那个决定两头都很硬:太长则 IP 层要分片,而任何一片丢失整个 IP 数据报都要丢弃(IP 不做分片重传),丢包率被放大;太短则一份数据要背 20 + 8 字节首部,线路上传的绝大部分是首部。
顺带澄清一处:面向报文不等于一定不分片。 UDP 自己既不合并也不拆分,但交给 IP 之后 IP 层照样可能分片;UDP 保留的是应用层看到的边界——IP 层会先重组再上交,应用拿到的仍是完整的一份。
还有一条行为要记:目的端口不存在时,UDP 丢弃报文并由 ICMP 回"端口不可达"(TCP 是自己回 RST,因为 UDP 首部里没有任何标志位能表达"拒绝")。traceroute 判断"已到终点"靠的正是这条。
三、UDP 首部格式
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 源端口号 | 目的端口号 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 长度 | 校验和 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+四个字段各 2 字节,合计 8 字节。源端口在需要对方回信时选用,不需要时可填全 0。
长度字段 = 首部 + 数据,最小值 8(仅有首部)。所以数据长度恒为
两处数字很容易记混,一起厘清:
1472 与 1480 不是一回事。 以太网上不触发 IP 分片时,UDP 数据的上限是
数据最大是 65527 还是 65507,取决于问的是哪个口径:只按 UDP 长度字段算是
拿 IP 总长度减去 IP 首部长度就能算出 UDP 数据报多长,长度字段看似冗余,但两个理由让它必须存在:① UDP 不应该去读 IP 首部,分层要求每层只依赖本层看得到的信息;② 校验和需要它——伪首部里要填 UDP 长度,若它只存在于 IP 首部,被改掉时就察觉不了。
四、校验和:伪首部到底在防什么
只校验 UDP 首部与数据,查出的是"内容在路上被改了"。把伪首部拼进来,多查出三类错:
| 多查出的错 | 靠什么拦住 |
|---|---|
| 送错主机:目的 IP 被改坏,分组送到了 C | C 用伪首部里自己的 IP 去算就对不上,丢弃。没有伪首部时 C 会以为这份数据本来就是给自己的 |
| 送错协议:协议字段被改成 17,TCP 报文段误交给 UDP | 协议号参与计算 |
| 长度被改 | 长度在 UDP 首部与伪首部里各出现一次,改一处必然不匹配 |
伪首部把校验从"内容对不对"升级成"是不是本来就该交给我"。
伪首部共 12 字节:源 IP 4 + 目的 IP 4 + 全零 1 + 协议号 1(UDP 填 17,TCP 填 6)+ UDP 长度 2。它既不向下传送也不向上递交,只在算校验和时临时拼在前面。
算法四步:字段置零 → 按 16 位分组(数据是奇数字节时末尾补一个全零字节)→ 带循环进位的反码求和(溢出的高位加回低位)→ 取反填入。
补的那个全零字节不发送,也不计入长度字段——所以奇数长度的数据报,长度字段永远是奇数。
接收端凭什么判无错:它把收到的校验和一并算进去,结果全 1(0xFFFF) 即无差错。道理在反码算术里——一个数加上自己的反码恒为全 1,所以接收端根本不必知道发送端原来算出的和是多少。
两条边界要记住。UDP 校验和是可选的,TCP 是强制的:UDP 不算时字段填 0;但若算出来的结果恰好是 0,要填全 1(0xFFFF),否则会被对方误当成"没算"。检错能力有边界:它能查出任何单比特翻转,但查不出两处互相抵消的差错(一个字加 1、另一个字减 1)。更强的检错要靠链路层的 CRC。
完整算一次 UDP 校验和(第一次学、或想手动跑一遍带循环进位的反码求和时展开)
主机 192.168.1.10 的 1025 端口向 192.168.1.20 的 53 端口发一个 UDP 数据报,数据部分是 5 个字节 N E T 4 0(ASCII 依次为 0x4E、0x45、0x54、0x34、0x30)。
第 1 步:先定长度。 数据 5 字节 + 首部 8 字节,长度字段 = 13(0x000D)。长度在 UDP 首部与伪首部里各出现一次,先算出来后面两处直接填,避免填成"数据长度 5"。
第 2 步:拼出参加计算的字节串。
| 段 | 内容(十六进制,按 16 位字分组) |
|---|---|
| 伪首部 12 字节 | C0A8 010A(源 IP 192.168.1.10) C0A8 0114(目的 IP 192.168.1.20) 0011(全零字节 0x00 + 协议号 17=0x11) 000D(UDP 长度 13) |
| UDP 首部 8 字节 | 0401(源端口 1025) 0035(目的端口 53) 000D(长度 13) 0000(校验和先置零) |
| 数据 5 字节 + 填充 | 4E45 5434 3000(末字节 0x30 后补一个全零字节) |
一共 26 字节 = 13 个 16 位字。补的那个 0x00 只用于凑够 16 位分组,不发送、也不算进长度字段——所以长度仍是 13 而不是 14。
第 3 步:逐字做带循环进位的加法。
| # | 加数 | 累计和 |
|---|---|---|
| 1 | C0A8 | C0A8 |
| 2 | 010A | C1B2 |
| 3 | C0A8 | 1825A → 进位回卷 → 825B |
| 4 | 0114 | 836F |
| 5 | 0011 | 8380 |
| 6 | 000D | 838D |
| 7 | 0401 | 878E |
| 8 | 0035 | 87C3 |
| 9 | 000D | 87D0 |
| 10 | 0000 | 87D0 |
| 11 | 4E45 | D615 |
| 12 | 5434 | 12A49 → 进位回卷 → 2A4A |
| 13 | 3000 | 5A4A |
进位要"加回低位"而不是丢掉,这是反码算术与普通补码加法的唯一区别:溢出的那个 1 代表
第 4 步:取反码填入。 求和结果
接收端复算。 把校验和字段照收到的值原样保留,连同伪首部再做一次反码求和:
再验它确实能查错:把数据首字节由 0x4E 改成 0x4F(只翻一位),第 11 个字变成 4F45,总和 +1 变成 5A4B,接收端算出 5A4B + A5B5 回卷后得 0100,不是全 1,检出差错。
教材对这套方法的评价是"检错能力并不强,但它的好处是简单,处理起来较快"。TCP 校验和用完全相同的算法与同样 12 字节伪首部,只把协议号 17 改成 6、UDP 长度改成 TCP 报文段长度。
五、何时选 UDP,可靠性该放哪一层
| 应用 | 端口 | 选择 UDP 的原因 |
|---|---|---|
| DNS | 53 | 一问一答、报文短,建连接开销比查询本身还大 |
| DHCP | 67/68 | 客户端尚无 IP,必须靠广播,TCP 不支持 |
| TFTP | 69 | 场景简单,可靠性交给应用层自己做 |
| 实时音视频 RTP | — | 重传回来的帧已经过期 |
| SNMP / RIP | 161 / 520 | 报文简短、周期性重发,丢一次下一周期自然更新 |
归纳成三条判据就能应对没见过的应用:重传是否还有意义 / 建连接开销是否超过数据本身 / 是否需要广播多播。任一成立即倾向 UDP。
UDP 本身不可靠,基于它的应用却可以很可靠:TFTP 在应用层做停止-等待,DNS 超时就重发查询,QUIC 在 UDP 之上重建了连接管理、可靠传输、拥塞控制与多路复用。"可靠"不是某一层的属性,而是某一层选择实现的机制。
那为什么不把可靠性全塞进传输层(想弄清何时该用 TCP、何时该自己在 UDP 上做时展开)
可靠性的实现方式与应用需求强相关:TFTP 需要的是"每块都确认",实时视频需要的是"丢了就算了但要有序",QUIC 需要的是"不同流互不阻塞"。TCP 只能提供一套固定的可靠性,谁也满足不了全部。UDP 把这个决定权交还给应用——这就是它存在的价值。
反过来也有边界:这不意味着"应用层做可靠性总是更好"。应用层做要自己维护序号、计时器、重传队列,重写一遍 TCP 已经解决过的问题;而且应用层看不到 RTT 的准确测量与网络拥塞信号,做出的重传策略往往比 TCP 更糟。所以判据是:需求与 TCP 提供的那套一致时用 TCP,明显不一致时才自己在 UDP 上做。
本节小结
- UDP 在 IP 之上只加了复用分用与差错检测两件事。 端口把数据从"主机"送到"进程",校验和补上 IP 首部检验和不覆盖数据部分的缺口;一份数据到进程要过两道分用关:先按协议字段(UDP = 17)挑协议,再按目的端口挑进程。
- 五个特点全部由"首部只有 8 字节"推出:放不下序号 → 无法确认与重传 → 不可靠、无拥塞控制。面向报文既不合并也不拆分,于是"报文该多大"被推给应用:太长会触发 IP 分片而丢一片废一报,太短则首部开销占比过高。
- 校验和覆盖伪首部 + 首部 + 数据,伪首部 12 字节不发送也不上交,作用是把校验升级成"是不是本来就该交给我"。算法是置零 → 16 位分组 → 带循环进位的反码求和 → 取反;接收端把收到的校验和一并算入,结果全 1 即无差错。
考点速记
UDP 在真题里被考过的形式有三种,三种问的都是"8 字节首部"这件事的三个不同后果:怎么算、开销多大、省下多少时间。
① 校验和的最后一步是什么(cn-2024-39)。给出中间结果 1011 1001 1011 0110,再加最后一个 16 位数 0110 0101 1100 0101,问最终的校验和。
两步都不能省:
答 C。四个选项精确对应四种做法:A 是既没回卷也没取反,B 是回卷了但忘了取反,D 是回卷时把进位加错了位再取反。B 这个干扰项最要命——算到 0x1F7C 就以为做完了,是这道题最容易停错的地方。填入首部的永远是"和的反码",不是和本身。
② 12 字节数据的传输效率(cn-2021-39)。同样 12 B 的应用层数据,分别用 1 个 UDP 数据报和 1 个 TCP 段传输,问最大传输效率。
答 D。两处要点:一是"最大"这个词——TCP 首部可以到 60 字节,只有取最小的 20 字节(不带任何选项)才是最大效率;二是分母只算传输层首部,题目问的是"该 UDP 数据报和 TCP 段"的效率,不含 IP 首部。选项里的 37.5% 出现了两次,就是给"把 UDP 也按 20 字节算"的人准备的。
③ 同一个服务,走 UDP 和走 TCP 各要多久(cn-2025-39)。客户向 Time 服务器请求时间,RTT = 8 ms,问分别走 UDP 与 TCP 所需的最少时间。
UDP:8 ms。 无连接,请求发出去、响应回来,正好 1 个 RTT。
TCP:16 ms。 必须先建连接。三次握手中,客户发 SYN、收 SYN+ACK 用掉 1 个 RTT;此后客户发出的第三次握手 ACK 可以携带数据(即请求本身),服务器收到后回响应,再用 1 个 RTT。合计 2 RTT = 16 ms。
答 B。这道题是"建连接的开销是否超过数据本身"这条判据的量化版——请求一次时间只要几个字节,为它多付一个 RTT 显然不划算,所以 Time 这类服务天然该走 UDP。
本篇练习区里还会出现两道题:cn-2014-39 问 UDP 的三条叙述哪几条正确,讲在 TCP 与 UDP 对比;cn-2025-39 的另一半(TCP 那一侧的 2 RTT)依赖三次握手的时序,讲在 TCP 连接管理。
易错:校验和的最后一步是取反。 算到求和结果就停下,正好落进干扰项。
易错:反码求和的进位要加回低位,不能丢。 丢了接收端就永远算不出全 1。
易错:算传输效率时 TCP 要取最小首部 20 字节(问"最大效率"),UDP 是固定 8 字节。
易错:走 TCP 要多付一个 RTT 建连接,但第三次握手的 ACK 可以携带数据,所以是 2 RTT 不是 2.5 RTT。
易错:长度字段 = 首部 + 数据,数据长度是
。以太网上数据上限 1472,但长度字段填 1480。
易错:奇数字节时补的那个全零字节不发送、不计入长度字段。
易错:UDP 校验和可选、TCP 强制;不算时填 0,算出来恰好是 0 则填全 1。
易错:面向报文不等于不分片。 UDP 自己不拆,但 IP 层照样可能分片。
易错:目的端口不存在时 UDP 借 ICMP 回"端口不可达",TCP 是自己回 RST。
教材出处
- 谢希仁《计算机网络》(第 8 版)p215(5.2.1 UDP 概述):"用户数据报协议 UDP 只在 IP 的数据报服务之上增加了很少一点的功能,这就是复用和分用的功能以及差错检测的功能。" 本篇第一节的整个框架就是这句话的展开。
- 同书 p216:面向报文的完整表述——"UDP 对应用层交下来的报文,既不合并,也不拆分,而是保留这些报文的边界……因此,应用程序必须选择合适大小的报文。若报文太长,UDP 把它交给 IP 层后,IP 层在传送时可能要进行分片,这会降低 IP 层的效率。反之,若报文太短……会使 IP 数据报的首部的相对长度太大"。第二节"报文太长 / 太短"两头的代价即出自此处。
- 同书 p212 脚注:"IP 层也有复用和分用的功能,即在发送方使用不同协议的数据都可以封装成 IP 数据报发送出去,而在接收方的 IP 层根据 IP 首部中的协议字段进行分用"——本篇"两道分用关"的依据。
- 同书 p212:"运输层还要对收到的报文进行差错检测……在网络层,IP 数据报首部中的检验和字段,只检验首部是否出现差错而不检查数据部分。" 这是"为什么 UDP 还要自己算一次校验和"的直接答案。
- 同书 p217(5.2.2 UDP 的首部格式):四个字段的定义,"长度 UDP 用户数据报的长度,其最小值是 8(仅有首部)"、"源端口 源端口号。在需要对方回信时选用。不需要时可用全 0"。
- 同书 p218:伪首部与校验和算法的完整描述——"所谓'伪首部'是因为这种伪首部并不是 UDP 用户数据报真正的首部……伪首部既不向下传送也不向上递交,而仅仅是为了计算检验和";"若 UDP 用户数据报的数据部分不是偶数个字节,则要填入一个全零字节(但此字节不发送)";"在接收方……按二进制反码求这些 16 位字的和。当无差错时其结果应为全 1";以及对检错能力的评价"这种简单的差错检验方法的检错能力并不强,但它的好处是简单,处理起来较快"。同页还给出"目的端口号不正确就丢弃该报文,并由 ICMP 发送'端口不可达'差错报文"。本篇折叠块里的算法与自检口径全部依此页。
- 同书 p228(5.5 TCP 报文段的首部格式,第 13 条"检验和"):TCP 校验和"要在 TCP 报文段的前面加上 12 字节的伪首部。伪首部的格式与图 5-5 中 UDP 用户数据报的伪首部一样。但应把伪首部第 4 个字段中的 17 改为 6(TCP 的协议号是 6),把第 5 字段中的 UDP 长度改为 TCP 长度"。
相关知识
TCP 与 UDP 对比|TCP 协议基础|IP 数据报格式|IP 分片|ICMP