UDP:极简的传输层

UDP(User Datagram Protocol)是传输层最简单的协议,只在 IP 之上加了最少的封装:

+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|     Source Port      |    Destination Port   |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|         Length          |       Checksum      |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                         Data                                  |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

头部只有 8 字节,对比 TCP 的 20 字节起步,UDP 几乎没有开销。

UDP 的特点

特性UDPTCP
连接方式无连接面向连接
可靠性不保证保证
有序性不保证保证
流量控制
拥塞控制
头部开销8 字节20+ 字节

UDP 的应用场景

UDP 并非"不可靠"的代名词,它适合以下场景:

  1. 实时音视频:延迟比完整性更重要(VoIP、直播)
  2. DNS 查询:单次请求-响应,不需要连接维护
  3. 游戏同步:状态更新频繁,旧数据无意义
  4. 物联网传感器:资源受限,简单通信
  5. 隧道协议:在 UDP 上构建自己的可靠性(QUIC、WireGuard)

QUIC:在 UDP 上重建一切

QUIC(Quick UDP Internet Connections)由 Google 提出,现已成为 HTTP/3 的基础。它在 UDP 之上实现了 TCP 的大部分功能,同时解决了 TCP 的历史包袱。

QUIC 解决了什么问题?

1. TCP 队头阻塞

TCP 中,一个连接上的所有流共享同一个有序队列。如果某个流的包丢失,后续所有流都必须等待:

TCP 连接上的流:
Stream A: [1] [2] [3] [4] [5]
Stream B: [1] [2] [3] [4] [5]

如果 Stream A 的第3个包丢失:
Stream A: [1] [2] [X] [4] [5]  ← 阻塞
Stream B: [1] [2] [3] [4] [5]  ← 即使全部到达也被阻塞!

QUIC 为每个流独立维护可靠性:

QUIC 连接上的流:
Stream A: [1] [2] [X] [4] [5]  ← 只有这个流阻塞
Stream B: [1] [2] [3] [4] [5]  ← 不受影响

2. 连接建立延迟

TCP + TLS 1.3:
  Client ──SYN──> Server          (1 RTT)
  Client <──SYN+ACK── Server
  Client ──ACK + ClientHello──>   (1 RTT)
  Client <──ServerHello── Server
  Client ──Finished──>            (1 RTT)
  Client <──Finished── Server
  总计: 2-3 RTT (TLS 1.3) 或 3-4 RTT (TLS 1.2)

QUIC:
  Client ──Initial (ClientHello + 加密)──> Server  (0-RTT 或 1 RTT)
  Client <──Initial (ServerHello + 加密)── Server
  总计: 1 RTT (首次), 0-RTT (恢复)

3. 连接迁移

TCP 连接由四元组标识:(源IP, 源端口, 目标IP, 目标端口)

当设备从 WiFi 切换到 4G,IP 地址变化,TCP 连接断开。

QUIC 使用 Connection ID 标识连接,与 IP 无关:

WiFi 环境:
  Connection ID=0xABC123, IP=192.168.1.100 → Server

切换到 4G:
  Connection ID=0xABC123, IP=10.0.0.50 → Server  ← 同一个连接!

QUIC 协议架构

┌─────────────────────────────────────┐
│            Application              │
│              (HTTP/3)               │
├─────────────────────────────────────┤
│              QUIC                    │
│  ┌─────────┐  ┌─────────┐  ┌──────┐│
│  │ Stream 1│  │ Stream 2│  │ ...  ││
│  └─────────┘  └─────────┘  └──────┘│
├─────────────────────────────────────┤
│         QUIC Transport              │
│   (连接管理、拥塞控制、流控)         │
├─────────────────────────────────────┤
│          TLS 1.3 (内置)             │
├─────────────────────────────────────┤
│              UDP                    │
├─────────────────────────────────────┤
│              IP                     │
└─────────────────────────────────────┘

关键点:QUIC 将 TLS 1.3 集成到了传输层,握手和加密协商在同一个过程中完成。

实际性能对比

在高延迟、高丢包环境下的测试(RTT=200ms, 丢包率=2%):

指标TCP + TLS 1.3QUIC
首字节延迟~600ms~200ms
并发流吞吐有队头阻塞无队头阻塞
连接恢复断开重连无缝迁移
慢启动从头开始恢复到上次窗口

抓包分析

QUIC 使用 UDP 端口 443,抓包命令:

# 抓取 QUIC 流量
tcpdump -i eth0 'udp port 443' -nn -w quic.pcap

# 使用 Wireshark 分析 QUIC
# 过滤器: quic
# 可以看到 Initial、Handshake、1-RTT 等包类型

QUIC 包的 UDP 载荷通常远大于单个 MTU(会进行分片),观察时注意:

# 查看 QUIC 连接的分片情况
tcpdump -i eth0 'udp port 443' -nn -v | grep "length"

Linux 内核对 QUIC 的支持

从 Linux 6.0 开始,内核原生支持 QUIC(目前是实验性的):

# 查看内核 QUIC 模块
lsmod | grep quic

# 加载模块(如果需要)
modprobe quic

# 使用内核 QUIC 的工具
apt install linux-tools-common

大多数用户态 QUIC 实现(如 quiche、msquic)仍然使用用户态 UDP socket,不依赖内核 QUIC 支持。

总结

QUIC 并非要替代 UDP,而是利用 UDP 的简单性,在用户态实现了现代化的传输协议。理解 UDP 的本质,才能真正理解 QUIC 的设计哲学。