UDP:极简的传输层
UDP(User Datagram Protocol)是传输层最简单的协议,只在 IP 之上加了最少的封装:
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Source Port | Destination Port |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Length | Checksum |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Data |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
头部只有 8 字节,对比 TCP 的 20 字节起步,UDP 几乎没有开销。
UDP 的特点
| 特性 | UDP | TCP |
|---|---|---|
| 连接方式 | 无连接 | 面向连接 |
| 可靠性 | 不保证 | 保证 |
| 有序性 | 不保证 | 保证 |
| 流量控制 | 无 | 有 |
| 拥塞控制 | 无 | 有 |
| 头部开销 | 8 字节 | 20+ 字节 |
UDP 的应用场景
UDP 并非"不可靠"的代名词,它适合以下场景:
- 实时音视频:延迟比完整性更重要(VoIP、直播)
- DNS 查询:单次请求-响应,不需要连接维护
- 游戏同步:状态更新频繁,旧数据无意义
- 物联网传感器:资源受限,简单通信
- 隧道协议:在 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.3 | QUIC |
|---|---|---|
| 首字节延迟 | ~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 的设计哲学。