跳转到主内容UDP | 物联网民工

UDP

TCP 越讲越重,UDP 却常被压缩成一句“无连接、不可靠”。这句话不算错,但太薄了。真正影响工程判断的,不是 UDP 少了哪些功能,而是它为什么故意不做这些功能,以及一旦它不做,哪些责任就会被重新压回应用或更上层协议。

DNS、DHCP、实时音视频、游戏协议、QUIC 都会站在 UDP 上,但它们显然不是同一种语义。这恰恰说明 UDP 提供的不是完整通信答案,而是一块足够薄、足够通用的底板:端口、多路复用、最小校验,剩下的交给上层自己决定。

UDP 的核心,不是“更快”,而是在 IP 之上只补最少的端口和校验语义,把连接状态、可靠性、顺序和重传控制留给应用或更高层协议自己承担

它为什么会出现

IP 负责把数据包尽力往前送,但它不区分不同应用,也不提供端到端的进程级交付。系统仍然需要一层最基本的传输语义,至少解决两件事:

  • 同一台主机上的不同应用怎样区分彼此流量
  • 数据报到达主机后应该交给哪个上层处理逻辑

TCP 选择在这层再补连接、重传、按序交付和窗口控制。UDP 则只保留最薄的一层:

  • 端口
  • 长度
  • 校验

这样做的意义在于,不是所有应用都值得背 TCP 那套状态和时延成本。

它是谁在什么背景下做出来的

UDP 同样来自早期互联网协议体系。它面对的不是“大家都想要可靠连接”,而是另一类长期存在的需求:

  • 有些交互只想发一个请求、收一个响应
  • 有些流量宁可丢一点,也不想为重传和排队付出更大时延
  • 有些协议要自己定义可靠性策略,而不是被 TCP 一次性打包决定

所以 UDP 不是“TCP 的残缺版”,而是一个刻意收缩职责的传输层选择。

先抓住它的主模型

UDP 可以先收成三件事:

  • 无连接
  • 面向消息的数据报
  • 不替应用保证可靠、有序和不重复

和 TCP 最大的区别不只是“有没有重传”,而是对象模型也不同:

  • TCP 交给应用的是字节流
  • UDP 交给应用的是一条条消息边界还在的数据报

这意味着 UDP 很适合“一次发一个问题、一次收一个回答”的场景,也意味着应用必须自己决定:丢了怎么办、乱了怎么办、重复了怎么办。

一次最常见的主链路

一个典型的 UDP 请求-响应路径可以压成这样:

sequenceDiagram participant C as 客户端 participant S as 服务器 C->>S: UDP Datagram(Request) S->>C: UDP Datagram(Response)

这条路径看起来很短,但它隐含的意思恰恰很多:

  • 不需要先建连接
  • 不需要在协议层维持长期状态
  • 发送方发出去之后,不知道对端是否一定收到
  • 如果响应没回来,应用必须自己决定是否超时和重试

所以 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 上重做一层传输

参考资料