TCP 越讲越重,UDP 却常被压缩成一句“无连接、不可靠”。这句话不算错,但太薄了。真正影响工程判断的,不是 UDP 少了哪些功能,而是它为什么故意不做这些功能,以及一旦它不做,哪些责任就会被重新压回应用或更上层协议。
DNS、DHCP、实时音视频、游戏协议、QUIC 都会站在 UDP 上,但它们显然不是同一种语义。这恰恰说明 UDP 提供的不是完整通信答案,而是一块足够薄、足够通用的底板:端口、多路复用、最小校验,剩下的交给上层自己决定。
UDP 的核心,不是“更快”,而是在 IP 之上只补最少的端口和校验语义,把连接状态、可靠性、顺序和重传控制留给应用或更高层协议自己承担
它为什么会出现
IP 负责把数据包尽力往前送,但它不区分不同应用,也不提供端到端的进程级交付。系统仍然需要一层最基本的传输语义,至少解决两件事:
- 同一台主机上的不同应用怎样区分彼此流量
- 数据报到达主机后应该交给哪个上层处理逻辑
TCP 选择在这层再补连接、重传、按序交付和窗口控制。UDP 则只保留最薄的一层:
- 端口
- 长度
- 校验
这样做的意义在于,不是所有应用都值得背 TCP 那套状态和时延成本。
它是谁在什么背景下做出来的
UDP 同样来自早期互联网协议体系。它面对的不是“大家都想要可靠连接”,而是另一类长期存在的需求:
- 有些交互只想发一个请求、收一个响应
- 有些流量宁可丢一点,也不想为重传和排队付出更大时延
- 有些协议要自己定义可靠性策略,而不是被 TCP 一次性打包决定
所以 UDP 不是“TCP 的残缺版”,而是一个刻意收缩职责的传输层选择。
先抓住它的主模型
UDP 可以先收成三件事:
- 无连接
- 面向消息的数据报
- 不替应用保证可靠、有序和不重复
和 TCP 最大的区别不只是“有没有重传”,而是对象模型也不同:
- TCP 交给应用的是字节流
- UDP 交给应用的是一条条消息边界还在的数据报
这意味着 UDP 很适合“一次发一个问题、一次收一个回答”的场景,也意味着应用必须自己决定:丢了怎么办、乱了怎么办、重复了怎么办。
一次最常见的主链路
一个典型的 UDP 请求-响应路径可以压成这样:
这条路径看起来很短,但它隐含的意思恰恰很多:
- 不需要先建连接
- 不需要在协议层维持长期状态
- 发送方发出去之后,不知道对端是否一定收到
- 如果响应没回来,应用必须自己决定是否超时和重试
所以 UDP 的“短路径”不是白拿来的,它是靠把复杂度往上层推换出来的。
为什么 UDP 不做连接和重传
如果 UDP 再把连接状态、重传、按序交付都做进去,它就会越来越像 TCP。可很多应用并不想要 TCP 那套统一决策。
例如:
- DNS 更关心低成本短查询,而不是长连接状态
- DHCP 初始接入时甚至还没有稳定的网络身份可维持连接
- 实时音视频有时宁可丢帧,也不想为旧数据重传增加时延
- QUIC 要自己定义一套比 TCP 更适合现代 Web 的恢复与多路复用逻辑
UDP 的价值,就在于它不替这些协议提前做决定。
为什么“轻”不等于自动更快
UDP 经常被直接理解成“比 TCP 快”,这个说法过于粗糙。
UDP 省掉的确实包括:
- 三次握手
- 连接状态维护
- 按序交付等待
- 传输层重传控制
但这不等于整体时延和性能一定更好,因为:
- 丢包后是否重试,可能还是要由应用自己补
- 大包仍会受 MTU、分片和中间设备影响
- 缺少拥塞控制的应用如果自己乱发,效果可能更差
- 真实业务的瓶颈常常不在“有没有握手”,而在网络质量和上层策略
所以 UDP 只是“让你有机会自己做得更合适”,不是“协议本身自动送你更快”。
为什么 DNS 和 DHCP 都偏爱 UDP
它们都很适合 UDP 的第一高频路径:短、小、一次问答。
DNS 的典型特点是:
- 查询报文短
- 请求-响应模型明确
- 大多数时候不值得为一次查询先建连接
DHCP 的初始发现阶段更典型:
- 客户端还没有稳定 IP
- 需要广播发现服务器
- 目标就是尽快完成一次接入期参数协商
这两类协议当然都可能在边界情况下转向 TCP 或更复杂路径,但它们默认偏 UDP,不是因为“不在乎可靠性”,而是因为先要把最高频路径的成本压低。
为什么 QUIC 也选 UDP
QUIC 站在 UDP 上,看起来像在“借一个壳”。但这个壳正好提供了它最想要的边界:
- 有端口
- 有数据报边界
- 不强加连接语义
- 不强加可靠性和顺序策略
这样 QUIC 就能在用户态自己重做:
- 握手
- 重传
- 拥塞控制
- 流级多路复用
- 连接迁移
如果直接站在 TCP 上,这些行为边界很难真正改掉。
UDP 最容易出问题的地方
丢了就真的丢了
UDP 协议层不会帮你补发。包如果没到,应用除非自己设计了超时、重试、冗余或纠错,否则事情就停在那里。
这意味着“UDP 不可靠”不是一个抽象评价,而是应用设计里的现实责任。
大包和分片风险更明显
UDP 很常被拿来发短消息,一旦应用开始发大包,问题就会迅速冒出来:
- 超过路径 MTU 就可能分片
- 任意一个分片丢失,整条消息就失败
- 某些中间设备对分片很不友好
所以很多 UDP 协议的真实工程经验都是:宁可自己切小,也别轻易把希望寄托在 IP 分片上。
中间网络不一定像对 TCP 那样友好
很多网络设备、NAT、ACL 和运营商策略对 UDP 的处理更保守。于是你会看到:
- 某些端口范围被限制
- 空闲映射更容易过期
- 对持续流量、突发流量和大包的处理差异更大
所以 UDP 的问题不只在协议本身,还在现实网络对它的支持质量。
抓包时真正该看什么
UDP 抓包不要一开始只看头字段。更有效的顺序通常是下面几步。
先看消息边界和端口
先确认:
- 谁发给谁
- 源端口和目标端口是什么
- 一次请求对应几次响应
因为 UDP 保留了消息边界,很多问题直接从“这一条报文有没有回来”开始判断,比 TCP 先看连接状态更直接。
再看有没有重试、重复和超时
UDP 协议层不负责重传,所以抓包里看到的重试常常是应用自己做的。这个时候要分清:
- 是应用超时后主动重发
- 还是网络里出现了重复包
- 还是服务端本身回了多份响应
这类区别会直接影响你判断责任是在应用、服务端,还是路径本身。
最后看 MTU、分片和路径限制
很多“偶发不通”“小包正常大包异常”的问题,往往不是应用逻辑抖动,而是:
- UDP 分片被丢
- NAT 映射超时
- 某段链路或设备对 UDP 大包、突发包更敏感
这些现象不先从 UDP 和 IP 层看,很容易在上层协议里绕半天。
今天工程上真正该怎么看 UDP
- 不要把 UDP 看成“天然更快的 TCP”,它只是把大量决策权还给上层
- 不要把 UDP 的无连接理解成“没有状态”,很多应用只是把状态转移到了自己手里
- 不要忽视消息边界,这是 UDP 和 TCP 在应用模型上的根本差异
- 不要把丢包、分片和 NAT 问题当成偶发现象,很多 UDP 故障都卡在这些现实边界上
- 不要因为协议头简单,就低估基于 UDP 的上层协议复杂度
继续阅读
- IP:UDP 之下负责可达性和分片边界的网络层
- NAT:为什么很多 UDP 故障会暴露成映射超时和打洞问题
- DNS:为什么经典短查询大量跑在 UDP 上
- DHCP:为什么初始接入要依赖 UDP 广播
- QUIC:为什么现代 Web 会站在 UDP 上重做一层传输