目录
- UDP 协议:简单到极致的传输层协议
- UDP 头部结构:只有 8 字节!
- 四字段详解
- 校验和的细节:伪头部(Pseudo-header)
- UDP 与 TCP 头部大小对比
- UDP 的工作原理与五大特性
- 五大核心特性一览
- 无连接的工作流程
- UDP 的典型应用场景
- 用 tcpdump 抓取真实的 UDP 包
- 让 UDP 变可靠:主流方案全景图
- 核心矛盾:为什么要给 UDP "穿铠甲"?
- 六大方案总览对比
- 各方案简要说明
- UDT(UDP-based Data Transfer)
- KCP(本文重点之一,下文会详解)
- QUIC(本文重点之二,下文会详解)
- enet
- RakNet
- 选型决策树
- KCP:为低延迟而生的可靠传输协议
- 设计哲学:以延迟换可靠性
- 协议内部架构:缓冲区模型
- 核心机制一:ARQ 快速重传
- 快速重传策略:不等超时的秘密武器
- 核心机制二:nodelay 模式的四大参数
- 核心机制三:流量控制 & 拥塞控制
- 拥塞控制,可关闭的杀手级特性
- 安全性:KCP 的安全层
- KCP 本质上只解决"可靠传输",不解决"安全传输"
- 解决方案:上层叠加加密层
- FEC 前向纠错(可选扩展模块)
- 性能基准数据
- 完整工作流程图
- QUIC:Google 革新 → IETF 标准 → HTTP/3 的基石
- 从 Google QUIC 到 IETF QUIC:发展时间线
- QUIC vs TCP + TLS:握手速度对比
- 核心特性一:TLS 1.3 内置加密(强制,不可关闭!)
- QUIC 的加密范围
- 核心特性二:Stream 多路复用无队头阻塞
- 核心特性三:Connection ID 连接迁移
- 协议阶段流转图
- HTTP/3 与 QUIC 的关系
- 用命令行测试 QUIC 连接
- 全面对比:谁才是你的最佳选择?
- KCP vs TCP 详细对比(12 维度)
- QUIC vs TCP (+ TLS) 详细对比(12 维度)
- 综合适用场景矩阵
- 总结
- 参考资源
- UDP 相关 RFC
- QUIC 相关 RFC(IETF 国际标准)
- TCP 相关 RFC(对比参考)
- KCP 参考资料( 非官方 RFC 规范)
- 其他参考资料
- 延伸阅读推荐 O3
你有没有想过,当你在玩王者荣耀时,技能释放几乎零延迟;当你用 Chrome 浏览网页时,首次加载快得惊人;当你用某款游戏加速器时,速度比直连还快。
它们背后用的都不是传统 TCP,而是基于 UDP 的自定义传输协议。
很多人知道”UDP 是不可靠的”、“UDP 比 TCP 快”,但真要细问:
既然 UDP 不可靠,那这些协议怎么做到数据不丢的? KCP 和 QUIC 到底有什么不同?什么场景该选哪个? 为什么 Google 要在 UDP 上重新造轮子,而不是直接优化 TCP?
今天这篇文章,我们从最底层出发,先把 UDP 协议本身彻底搞懂,然后系统梳理六大基于 UDP 的可靠传输方案,重点对比 KCP 与 QUIC 的原理和实现细节,最后咱一起研究下到底该选 TCP 还是 UDP 可靠传输。
UDP 协议:简单到极致的传输层协议
UDP 头部结构:只有 8 字节!
在讲”如何让 UDP 变可靠”之前,我们得先理解 UDP 本身长什么样。
UDP 数据报格式 (RFC 768)
0 7 8 15 16 23 24 31
+--------+--------+--------+--------+
| Source | Destination | 源端口 (16位) | 目的端口 (16位)
| Port | Port |
+--------+--------+--------+--------+
| Length | Checksum | 长度 (16位) | 校验和 (16位)
+--------+--------+--------+--------+
|
| data octets ... |
| ... |
+-----------------------------------+
没错,整个头部只有 4 个字段,固定 8 字节。 对比 TCP 的 20~60 字节(20 字节固定头 + 最多 40 字节选项),UDP 简洁到极致。
四字段详解
| 字段 | 长度(bit) | 含义 | 说明 |
|---|---|---|---|
| 源端口(Source Port) | 16 | 发送方端口号 | 可选字段,设为 0 时表示不需要返回信息 |
| 目的端口(Destination Port) | 16 | 接收方端口号 | 必须填写,用于将数据交给正确的应用进程 |
| 长度(Length) | 16 | UDP 数据报总长度 | 包含 8 字节首部 + 数据部分,最小值为 8(仅首部无数据) |
| 校验和(Checksum) | 16 | 错误检测码 | 用于检查传输过程中是否出错 |
小知识 , 为什么源端口是可选的?
当你用 DNS 查询域名时,客户端发送请求需要填源端口(操作系统自动分配临时端口),因为服务器需要知道把回复发给谁。
但某些场景(如 DHCP 客户端发现),客户端还没有 IP 地址,此时设为 0 表示”我不需要回复”。这就是为什么 UDP 允许省略源端口。
校验和的细节:伪头部(Pseudo-header)
校验和是 UDP 中最值得深挖的字段,它有一个特殊设计,伪头部:
计算校验和时的"伪头部"(不实际传输,仅用于计算):
┌─────────────────────────────────────┐
│ 伪头部 (Pseudo-header) │
├─────────────────┬───────────────────┤
│ Source IP Addr │ Destination IP Addr│ 来自 IP 层头部
├─────────────────┼───────────────────┤
│ Zero (8 bits) │ Protocol (8 bits) │ 协议号 = 17 (UDP)
├─────────────────┴───────────────────┤
│ UDP Length (16 bits) │ UDP 报文总长度
└─────────────────────────────────────┘
↓ 拼接 ↓
┌─────────────────────────────────────┐
│ UDP 真正的首部 │ (8字节)
├─────────────────┬───────────────────┤
│ Src Port(16) │ Dst Port(16) │
├─────────────────┼───────────────────┤
│ Length (16) │ Checksum (16) │
└─────────────────┴───────────────────┘
↓ 拼接 ↓
┌─────────────────────────────────────┐
│ Data (数据) │
└─────────────────────────────────────┘
校验和 = 对以上所有内容(伪头部 + UDP首部 + Data)求补码和
为什么要引入伪头部? 因为 IP 层本身不做端到端的校验(IP 头部有校验但只覆盖 IP 头)。如果不加伪头部,UDP 无法检测到”数据包被错误路由到另一个地址”的情况,比如路由表出错导致包被送到了错误的主机。
IPv4 vs IPv6 的关键差异:
- IPv4:校验和是可选项!可以设为全 0 来跳过校验(很多旧系统这样做以提升性能)。接收方看到全 0 就不检查了。
- IPv6:UDP 校验和是强制的,不可关闭!因为 IPv6 头部本身就没有校验和字段(为了简化路由器处理),所以必须依赖上层协议来做完整性检查。
这意味着在 IPv6 网络中,UDP 的校验和必须正确计算,否则包会被直接丢弃。
UDP 与 TCP 头部大小对比
┌──────────────────────────────────────────────────┐
│ TCP 头部 (20 ~ 60 字节) │
│ ┌──────┬──────┬──────┬──────┬──────┬───┬─────────┐│
│ │SrcPt │DstPt │ Seq │ Ack │Flags│Wnd│ Options ││ 固定20字节 + 选项0~40字节
│ │ 16b │ 16b │ 32b │ 32b │ 16b │16b│ 0~320b ││
│ └──────┴──────┴──────┴──────┴──────┴───┴─────────┘│
└──────────────────────────────────────────────────┘
vs
┌──────────────────────────────────────────────────┐
│ UDP 头部 (固定 8 字节) │
│ ┌──────┬──────┬──────┬──────┐ │
│ │SrcPt │DstPt │Length│Check │ │ 固定8字节,无任何选项
│ │ 16b │ 16b │ 16b │ 16b │ │
│ └──────┴──────┴──────┴──────┘ │
└──────────────────────────────────────────────────┘
结论:
- UDP 头部: 固定 8 字节 (无变化)
- TCP 头部: 20 ~ 60 字节 (取决于选项)
- UDP 比 TCP 小: 60% ~ 75%!
- 在大量小包场景下,节省的开销非常可观
UDP 的工作原理与五大特性
五大核心特性一览
UDP 的五大特性
┌─────────────────────────────────────────────────┐
│ │
│ ① 无连接 → 不需要握手,想发就发 │
│ ② 不可靠 → 不确认、不重传、不排序、不流控 │
│ ③ 低开销 → 仅 8 字节首部,无状态维护开销 │
│ ④ 广播/多播 → 天然支持一对多通信 │
│ ⑤ 面向报文 → 保留应用层消息边界 │
│ │
└─────────────────────────────────────────────────┘
| # | 特性 | 详细说明 | 生活类比 |
|---|---|---|---|
| 1 | 无连接(Connectionless) | 不需要像 TCP 那样建立连接,应用层数据下来后直接加上 UDP 头就发出去了 | 寄明信片 vs 打电话,明信片扔进邮筒就走,不需要对方”接电话”确认 |
| 2 | 不可靠(Unreliable) | 不做确认(ACK)、不做重传、不做排序、不做流量控制。发了就是发了,丢没丢不知道 | 广播喊话,喊完不管别人听没听到 |
| 3 | 低开销(Low Overhead) | 仅 8 字节固定首部,无选项字段;无需维护连接状态、滑动窗口、拥塞控制等复杂机制 | 轻装上阵,只带必需品上路 |
| 4 | 支持广播/多播(Broadcast/Multicast) | 利用 UDP 可以向同一网络的所有主机(广播)或一组主机(多播)发送消息 | 组长通知组员,一次说话所有人都能听到 |
| 5 | 面向报文(Message-Oriented) | 保留应用层的消息边界,不会像 TCP 那样合并/拆分数据 | 快递整件送达,发什么收什么,不拆不拼 |
无连接的工作流程
TCP 的通信流程 (三次握手):
Client Server
| |
| -------- SYN -------> | ① 客户端发起连接
| <---- SYN+ACK ------- | ② 服务端同意
| -------- ACK -------> | ③ 双方确认建立
| ===== 连接建立完成 === | (已消耗 1.5 RTT)
| ---- [数据] -------> | ④ 开始传输
| <--- [ACK] --------- |
UDP 的通信流程 (无握手):
Client Server
| |
| ---- [UDP数据] -----> | 直接发送! 无需任何前置步骤!
| | 服务端收到就处理, 没收到就算了
| ---- [UDP数据] -----> | 每个包独立, 互不影响
| |
关键区别:
- TCP: 先建立"管道", 再流水式传输
- UDP: 每个"信封"独立邮寄, 互不相干
面试常考题:UDP 为什么比 TCP 快?
不仅仅是头部小的原因。完整答案是:
- 无连接建立:TCP 需要 1~3 次 RTT 握手,UDP 为 0
- 无确认重传:TCP 每个包都需要 ACK,超时要重传,UDP 不管
- 无拥塞控制:TCP 有慢启动/拥塞避免/快速恢复,UDP 全速发送
- 无排序:TCP 要按序交付(可能因等待乱序包而延迟),UDP 收到就交上去
- 头部开销小:UDP 8 字节 vs TCP 20~60 字节
但这些”优势”同时也是”劣势”,后面我们讲的 KCP/QUIC,本质上就是在找回那些被丢弃的能力,同时尽量保留低延迟的优势。
UDP 的典型应用场景
了解了 UDP 的特性之后,哪些场景适合用它呢?
| 协议/应用 | 端口 | 场景说明 | 为什么选 UDP |
|---|---|---|---|
| DNS | 53 | 域名解析 | 查询包极小(几十字节),追求低延迟,丢了重查就行 |
| DHCP | 67/68 | 动态 IP 分配 | 客户端刚接入网络时还没有 IP 地址,无法建立 TCP 连接 |
| NTP | 123 | 网络时间同步 | 时间同步对延迟敏感,且”过期的精确时间”毫无意义 |
| VoIP / RTP | 随机 | 实时音视频通话 | 迟到的语音包没用,宁可丢包也不能卡顿 |
| 在线游戏 | 随机 | FPS / MOBA / RTS | 技能释放要求毫秒级响应,可容忍偶尔丢包 |
| TFTP | 69 | 简单文件传输 | 嵌入式场景,协议极简,适合引导加载 |
| SNMP | 161 | 网络设备管理 | 管理信息简短,网络故障时仍需可达 |
| QUIC / HTTP/3 | 443 | 现代网页浏览 | 在 UDP 上实现了可靠加密传输(本文重点之一!) |
用 tcpdump 抓取真实的 UDP 包
理论讲完了,来点实操。在 Linux/macOS 上你可以用 tcpdump 直接抓取 UDP 包:
# ============================================
# 示例 1: 抓取 DNS 查询的 UDP 包(最常见的 UDP 应用)
# ============================================
# 在终端 A 启动抓包(需要 root 权限)
sudo tcpdump -i any udp port 53 -nn -X -c 5
# 参数解释:
# -i any : 监听所有网络接口
# udp port 53: 只捕获 UDP 53号端口(DNS)
# -nn : 不解析域名和服务名(显示原始 IP 和端口)
# -X : 以十六进制和 ASCII 同时显示数据内容
# -c 5 : 只抓 5 个包后就停止
# 在终端 B 执行一次 DNS 查询触发流量
dig www.baidu.com A +short
# 或者用 nslookup
nslookup www.google.com
抓包结果示例(简化展示):
# 抓到的 DNS 请求包 (UDP):
14:23:45.123456 IP 192.168.1.100.54321 > 8.8.8.8.53:
0x0000: 4500 003c 1a2b 4000 4011 b8c0 c0a8 0164
0x0010: 0808 0808 d431 0035 0028 ea9f 0100 0001
...
↑ 解读:
- 4500: IPv4 版本4, IHL=5(20字节)
- 003c: 总长度=60字节 (IP头20 + UDP头8 + DNS查询32)
- 11: 协议号=17 (UDP!)
- c0a8 0164: 源IP=192.168.1.100
- 0808 0808: 目标IP=8.8.8.8
- d431: 源端口=54321 (随机临时端口) ← UDP源端口
- 0035: 目标端口=53 (DNS) ← UDP目的端口
- 0028: UDP长度=40 (8字节头+32字节数据) ← UDP长度
- ea9f: 校验和 ← UDP校验和
- 后面是 DNS 查询数据: www.baidu.com 的查询...
# ============================================
# 示例 2: 查看/调整 UDP 缓冲区参数
# ============================================
# 查看 UDP 接收缓冲区最大值(单位: 字节)
sysctl net.core.rmem_max
# 默认值通常: net.core.rmem_max = 212992 (约 208KB)
# 查看 UDP 发送缓冲区最大值
sysctl net.core.wmem_max
# 默认值通常: net.core.wmem_max = 212992 (约 208KB)
# 如果你的应用需要处理高速 UDP 流量(如视频直播、KCP 传输),
# 可能需要调大缓冲区防止丢包:
sudo sysctl -w net.core.rmem_max=26214400 # 接收缓冲区改为 25MB
sudo sysctl -w net.core.wmem_max=26214400 # 发送缓冲区改为 25MB
# 永久生效: 写入 /etc/sysctl.conf
# echo "net.core.rmem_max=26214400" | sudo tee -a /etc/sysctl.conf
# ============================================
# 示例 3: 用 nc (netcat) 快速测试 UDP 通信
# ============================================
# 终端 A: 启动一个 UDP 监听服务
nc -u -l -p 9999
# 终端 B: 向该端口发送 UDP 数据
echo "Hello UDP!" | nc -u 127.0.0.1 9999
# 终端 A 会显示: Hello UDP!
# 注意: 如果终端 A 没启动就发数据, 数据会静默丢弃 (这就是"不可靠")
重要提醒:UDP 的”不可靠”是双刃剑
优点:
- 速度快:无握手延迟,无等待确认的时间开销
- 简单:实现简单,调试方便
- 灵活:支持广播和多播
- 高效:小包场景下头部开销占比极低
缺点:
- 可能丢包:网络拥堵时包会被路由器直接丢弃
- 可能乱序:不同路径到达顺序可能不同
- 可能重复:底层网络可能会复制包
- 无流控:发送太快会把接收方淹没
思考题:如果我想用 UDP 的速度优势,但又需要数据的可靠性怎么办?
, 这正是下一章要解决的问题:在 UDP 之上构建可靠的传输层。
让 UDP 变可靠:主流方案全景图
核心矛盾:为什么要给 UDP "穿铠甲"?
上一章我们说 UDP 天生不可靠,不确认、不重传、不排序、不流控。但现实世界中,很多场景既需要低延迟,又需要数据可靠性。
┌─────────────────────────────────────────────────────┐
│ │
│ TCP: ✅ 可靠 ✅ 有序 ✅ 流控 │
│ ❌ 延迟高(握手+重传) │
│ ❌ 队头阻塞 │
│ ❌ 拥塞控制不可定制 │
│ │
│ UDP: ✅ 低延迟 ✅ 简单 ✅ 支持广播 │
│ ❌ 不可靠 ❌ 无序 ❌ 无流控 │
│ │
│ ───────────────────────────────── │
│ 能不能兼顾: 低延迟 + 可靠性 + 安全性? │
│ → 在 UDP 上叠加自定义的可靠性机制! │
│ │
└─────────────────────────────────────────────────────┘
TCP 的固有局限驱动了替代方案的出现:
| TCP 的痛点 | 具体表现 | 谁在意? |
|---|---|---|
| 拥塞控制不可修改 | 内核协议栈硬编码了 Cubic/BBR 等算法,应用层难以自定义 | 游戏开发者、音视频工程师 |
| 队头阻塞(HOL Blocking) | 一个包丢失会阻塞后续所有包的交付 | HTTP/2 用户(尤其移动网络) |
| 三次握手开销 | 短连接场景下握手占比极高 | API 调用、频繁请求 |
| 连接由四元组标识 | WiFi ↔ 4G 切换导致连接断开 | 移动端用户 |
| TIME_WAIT 等待 | 高并发短连接耗尽端口资源 | 服务器运维 |
这些痛点催生了多种”UDP + 自定义可靠性 + 安全性”的方案。下面我们逐一介绍。
六大方案总览对比
| 维度 | RUDP | UDT | KCP | QUIC | enet | RakNet |
|---|---|---|---|---|---|---|
| 核心定位 | 教学/基础实现 | 大数据高速传输 | 低延迟实时传输 | Web 下一代标准 | 游戏轻量库 | 游戏完整框架 |
| 诞生时间 | ~1980s (概念) | 2004 | 2013 | 2013 (Google) / 2021 (IETF) | ~2005 | 2000s |
| 可靠性机制 | 停等 ARQ / 回退 N | SACK + 可调窗口 | ARQ + SACK + 快速重传 | ACK + SACK + FEC | 可靠/不可靠混合通道 | 排序 ACK 系统 |
| 拥塞控制 | 无 | 自定义 CC 算法 | 可配置,甚至可关闭 | BBR/Cubic/NewReno 可插拔 | 无 | 内置有 |
| 安全性 | 无 | 可选加密(非内置) | 需上层叠加加密 | TLS 1.3 内置(强制) | 可选 AES 加密模块 | RakNetSSL 插件 |
| 标准化程度 | 无 RFC(教学概念) | RFC 相关草案 | 无 RFC(GitHub 开源项目) | RFC 9000 / 9001 / 9002 | 无(开源 C 库) | 无(商业/开源混合) |
| 多路复用 | 单流 | 单流 | 单流 | Stream 多路复用(无 HOL) | 通道(Channel) 机制 | 可靠/不可靠通道分离 |
| 连接迁移 | 不支持 | 不支持 | 不支持 | 支持(Connection ID) | 不支持 | 不支持 |
| 握手延迟 | 0(无握手) | ~1 RTT | ≈ 0(无需握手) | 1 RTT(首次)/ 0 RTT(复用) | ≈ 0 | ~1 RTT |
| 典型场景 | 学习 ARQ 原理 | 科学计算/大数据同步 | 音视频通话/在线游戏/VPN | HTTPS/Web API/MOBA/FPS | Unity 多人游戏 | |
| 成熟度/生态 | 教学级 | 中(科研领域) | 中高(国内广泛使用) | 高(HTTP/3 标准) | 低(维护停滞) | 中(Unity 收购后) |
关于”标准化程度”的理解:
- RFC 标准(如 QUIC):意味着跨厂商互操作性,Chrome 和 Nginx 可以无缝通信,因为双方都实现了同一个 RFC 规范。
- 开源项目(如 KCP/enet):意味着你需要在客户端和服务端都集成同一套 SDK,没有”标准互操作”的概念。
- 商业方案(如 RakNet):可能需要付费授权,但提供完整的技术支持和工具链。
各方案简要说明
RUDP(Reliable UDP) 最基础的”可靠 UDP”实现思路,在 UDP 之上手动加上序列号、确认应答和超时重传。
RUDP 工作流程:
发送方: [数据] + [SeqNum=1] → UDP → 网络
接收方: 收到 Seq=1, 回复 ACK=2
发送方: 收到 ACK=2, 发送 Seq=2 ...
如果超时没收到 ACK → 重传!
特点:
- 实现简单, 适合学习 ARQ (自动重传请求) 原理
- 通常使用停等协议 (Stop-and-Wait) 或回退 N (Go-Back-N)
- 生产环境很少直接使用 (太简陋)
UDT(UDP-based Data Transfer)
专为大数据高速传输设计的协议,常用于地理信息科学、基因数据分析等需要传输海量数据的领域。
UDT 特点:
- 基于 UDP, 但实现了类似 TCP 的可靠性和拥塞控制
- 拥塞控制算法针对高速广域网优化 (不同于 TCP 的 Cubic)
- 支持海量数据传输 (TB 级别)
- 典型应用: 科学计算网格、卫星数据回传
性能对比 (在高带宽高延迟链路上):
TCP 吞吐: ~50 Mbps (受 BDP 限制)
UDT 吞吐: ~900 Mbps (接近线路容量)
→ UDT 在长肥管道 (Long Fat Pipe) 场景下远优于 TCP
KCP(本文重点之一,下文会详解)
由中国开发者 skywind3000 于 2013 年创建的开源项目,专注于低延迟可靠传输。国内广泛应用于游戏加速器、实时音视频、VPN 等领域。
QUIC(本文重点之二,下文会详解)
由 Google 提出,经 IETF 标准化后的下一代传输协议,已成为 HTTP/3(RFC 9114)的底层传输层。Chrome/Firefox/Edge/Safari 已全面支持。
enet
一款轻量级的C 语言网络库,专门为实时多人游戏设计,提供了可靠的有序传输和不可靠的无序传输两种模式。
RakNet
功能完整的游戏网络引擎,曾用于《 Minecraft 》主机版、《 消逝的光芒》等知名游戏。2021 年被 Unity 收购后以开源形式发布(GPLv2 协议)。
选型决策树
面对这么多方案,实际项目中该怎么选?
你的核心需求是什么?
│
┌─────────────────┼─────────────────┐
▼ ▼ ▼
需要 Web 浏览器 追求极致低延迟 大数据传输
/HTTPS 兼容? (实时交互)? (GB/TB级别)?
│ │ │
▼ ▼ ▼
┌───┴───┐ ┌──────┴──────┐ ┌──────┴──────┐
│ 能否集 │ │ 只做游戏吗? │ │ 是否需要标 │
│成SDK? │ │ │ │准化互操作? │
└───┬───┘ └──────┬──────┘ └──────┬──────┘
是 ↓ 否 ↓ 是 ↓ 否 ↓ 是 ↓ 否 ↓
│ │ │ │ │ │
KCP QUIC enet/ KCP UDT 自定义/
(国内用) (HTTP/3) RakNet (通用) (科学计算) RUDP
一句话速查表:
| 如果你是…… | 推荐方案 | 原因 |
|---|---|---|
| Web 开发者(API/网页服务) | QUIC (HTTP/3) | 浏览器原生支持,零集成成本 |
| 游戏开发者(MOBA/FPS) | KCP 或 enet/RakNet | 极致低延迟,可控性强 |
| 音视频工程师(VoIP/直播) | KCP | 延迟敏感 + 可自建安全层 |
| VPN/加速器开发者 | KCP | 抗丢包能力强,可关闭拥塞控制 |
| 科学计算/大数据工程师 | UTD | 高速广域网传输优化 |
| 学生/学习者 | RUDP | 最简 ARQ 实现,适合理解原理 |
KCP:为低延迟而生的可靠传输协议
重要声明:KCP 没有官方 RFC 规范。
它是由中国开发者 skywind3000 于 2013 年创建的开源项目(C 语言实现,约 5000 行代码),代码托管于:
https://github.com/skywind3000/kcp
本文技术细节以作者 wiki 和源码为准。KCP 在国内游戏、音视频、VPN 领域有广泛使用,但请注意其非标准协议的性质,这意味着你需要客户端和服务端都集成同一套 KCP 库。
设计哲学:以延迟换可靠性
理解 KCP 的核心在于理解它和 TCP 的设计目标差异:
┌──────────────────────┬──────────────────────────┬──────────────────────┐
│ │ TCP │ KCP │
├──────────────────────┼──────────────────────────┼──────────────────────┤
│ 设计优先级 │ 公平性 > 吞吐量 > 延迟 │ 延迟 > 吞吐量 > 公平性 │
│ 核心目标 │ 最大化带宽利用率 │ 最小化传输延迟 │
│ 重传时机 │ 等超时(RTO) 或 3个重复ACK │ **不等超时,主动快速重传**│
│ ACK 策略 │ 延迟 ACK (合并确认) │ **立即 ACK (可配置)** │
│ Nagle 算法 │ 默认开启(合并小包) │ **不使用 Nagle** │
│ 拥塞控制 │ 内核强制,不可关闭 │ **可配置,甚至可完全关闭**│
│ 适用场景 │ 文件下载 / 网页浏览 │ 游戏 / 音视频 / 实时通信 │
└──────────────────────┴──────────────────────────┴──────────────────────┘
一句话总结:
TCP: "我要公平地使用网络,宁可慢一点也不能抢别人的带宽"
KCP: "我要最快地送达数据,可以牺牲一点公平性换取低延迟"
协议内部架构:缓冲区模型
KCP 的数据流转依赖于一套精心设计的缓冲区系统:
发送端 (Sender) 接收端 (Receiver)
┌─────────────┐ ┌─────────────┐ ┌──────────────────┐
│ 应用层调用 │ │ send_q │ │ │
│ikcp_send() │ ──→ │ (发送队列) │ │ │
└─────────────┘ └──────┬──────┘ │ │
│ flush()时 │ │
▼ │ │
┌─────────────┐ │ ┌─────────────┐
│ snd_queue │ │ │ rcv_queue │
│ (待发送队列) │─────┼UDP─┼→│ (接收队列) │
└──────┬──────┘ │ │ │
│ │ └──────┬──────┘
▼ UDP发送 │ │ ikcp_recv()
┌─────────────┐ │ ▼
│ snd_buf │ │ ┌─────────────┐
│ (发送缓冲区) │◀────┼────│ ackbuf_list │
│ (已发待确认) │ ACK │ │ (收到ACK列表)│
└─────────────┘ │ └─────────────┘
│ │ │
│ │ ▼ 回复ACK
┌────┴────┐ │ ┌─────────────┐
│ unack_ │ │ │ rcv_buf │
│ list │ │ │ (接收缓冲区) │
│ (已发未确认│ │ │ (乱序重组) │
│ 的包) │ │ └─────────────┘
└──────────┘ │
│
数据流向说明:
① ikcp_send(data): 用户数据 → send_q
② ikcp_flush(): send_q → snd_queue → 封装KCP头 → UDP发出 → 进入snd_buf等待确认
③ 收到对方ACK: 从snd_buf移除已确认的包
④ 接收方收到: 数据进入rcv_buf(可能乱序) → 排序后入rcv_queue
⑤ ikcp_recv(): 从rcv_queue取数据交给应用层
⑥ 接收方同时生成ACK回传发送方
关键理解:send_q 和 snd_queue 是一回事吗?
不是。send_q 是用户数据的”蓄水池”,flush() 时才从中取数据封装成 KCP 包放入 snd_queue。这种设计允许应用层在任何时间调用 ikcp_send() 而不需要关心底层是否正在发包,类似 TCP 的写缓冲区概念。
核心机制一:ARQ 快速重传
三种确认模式 KCP 提供三种不同粒度的确认机制:
| 模式 | 全称 | 工作方式 | 开销 | 适用场景 |
|---|---|---|---|---|
| UNA | Unacknowledged | 只确认最后一个连续收到的序号 | 最小(1个序号) | 无丢包的理想环境 |
| ACK | Acknowledge | 独立确认每个收到的包 | 中等(每包1个ACK) | 一般场景 |
| SACK | Selective ACK | 选择性确认 + 标记丢失范围 | 较大(携带丢包信息) | 高丢包环境 |
SACK 工作示意:
发送方发送: [1] [2] [3] [4] [5]
接收方收到: [1]✅ [2]✅ [3]❌丢了! [4]✅ [5]✅
传统 ACK: 只能说 "我收到了1和2, 下一个请发3"
→ 发送方不知道4和5也收到了, 可能重传[3][4][5]
KCP SACK: 可以说 "我收到了1~2, 4~5, 3丢了"
→ 发送方只需重传 [3] ✅ 效率高!
快速重传策略:不等超时的秘密武器
这是 KCP 与 TCP 最大的区别之一。
时间轴 →
TCP 的重传行为:
|---发送pkt1--|--发送pkt2--|--发送pkt3✗--|..................等RTO(200ms+)..............|
|--重传pkt3--|
↑ TCP 必须等到超时(RTO)或收到3个重复ACK才能重传
KCP 的快速重传 (interval模式):
|---发送pkt1--|--发送pkt2--|--发送pkt3✗--|-10%-重传-|-20%-重传-|(收到ACK停止)-|
↑ 每过 interval 比例的时间就主动重传一次!
↑ 即使 RTO 还没到!
关键参数:
- interval: 内部工作频率 (默认10ms, 即每秒更新100次)
- resend: 每个 RTT 内的快速重传次数 (默认2次)
- nodelay: 是否启用无延迟模式
实际效果:
TCP 丢包恢复: 通常需要 200ms ~ 2s (取决于RTO)
KCP 丢包恢复: 通常 < 30ms (快速重传)
→ 快 7 倍以上!
核心机制二:nodelay 模式的四大参数
KCP 提供了一个强大的配置接口 ikcp_nodelay(),这是调优的核心:
// 函数原型 (官方 API)
int ikcp_nodelay(ikcpcb *kcp, int nodelay, int interval, int resend, int nc);
| 参数 | 类型 | 含义 | 取值范围 | 推荐值 | 说明 |
|---|---|---|---|---|---|
| nodelay | int | 是否启用无延迟模式 | 0 或 1 | 1 | 0=正常模式(类似TCP),1=取消延迟ACK和Nagle |
| interval | int | 内部工作时钟频率(毫秒) | 1 ~ 5000 | 10 | 每 N ms 调用一次 ikcp_update();KCP 库默认约 100ms,低延迟场景建议设为 10ms(即每秒100次) |
| resend | int | 快速重传次数(每个 RTT 内) | 0 ~ ~10 | 2 | 0=仅超时重传(退化为类TCP),2=激进快速重传 |
| nc (no congestion) | int | 是否关闭拥塞控制 | 0 或 1 | 看场景 | 0=保留拥塞控制,1=完全关闭(杀手特性) |
// ===== 典型配置示例 =====
// 场景1: 极速模式 — 追求最低延迟(牺牲公平性)
// 适用: 专用链路 / 内网游戏 / VPN 加速器
ikcp_nodelay(kcp, 1, 10, 2, 1);
// 解释:
// nodelay=1 → 不延迟ACK, 不做Nagle合并
// interval=10 → 10ms刷新一次 (高灵敏度)
// resend=2 → 每RTT内快速重传2次 (激进)
// nc=1 → 关闭拥塞控制! 全速前进!
// 场景2: 平衡模式 — 速度与公平性的折中
// 适用: 公网音视频通话 / 跨网传输
ikcp_nodelay(kcp, 1, 20, 2, 0);
// 解释:
// interval=20 → 20ms刷新 (降低CPU占用)
// nc=0 → 保留拥塞控制 (不做网络破坏者)
// 场景3: 保守模式 — 类似TCP行为
// 适用: 不确定网络状况时的默认值
ikcp_nodelay(kcp, 0, 50, 0, 0);
// 解释:
// nodelay=0 → 使用延迟ACK (减少ACK数量)
// interval=50 → 50ms刷新 (低CPU)
// resend=0 → 不做快速重传 (仅超时重传)
// nc=0 → 保留拥塞控制
核心机制三:流量控制 & 拥塞控制
流量控制 KCP 的流量控制基于滑动窗口机制,与 TCP 类似但更灵活:
发送窗口 = min(对端通告的接收窗口(rwnd), 自身拥塞窗口(cwnd))
可通过以下 API 配置:
ikcp_wndsize(kcp, snd_wnd, rcv_wnd);
// snd_wnd: 发送窗口大小 (数据包个数, 不是字节数!)
// rcv_wnd: 接收窗口大小 (同上)
典型设置:
ikcp_wndsize(kcp, 256, 256); // 各256个包的窗口
// 每个包最大约 1400字节 (MTU - IP头 - UDP头 - KCP头)
// → 窗口容量 ≈ 256 × 1400 ≈ 358KB
拥塞控制,可关闭的杀手级特性
这是 KCP 区别于 TCP 的最关键设计决策:
TCP 的拥塞控制 (强制开启, 无法关闭):
┌─────────────────────────────────────┐
│ cwnd (拥塞窗口) │
│ │
│ 64| * │
│ | * * │ ← 慢启动 (指数增长)
│ 32| * * │
│ | * * │
│ 16|-------*---------------*-----------│← ssthresh (阈值)
│ | * * │ ← 拥塞避免 (线性增长)
│ 8| * * │
│ | * * │
│ 1|* │
│ +--------------------------------→ 时间
│ 发现丢包? cwnd 直接减半! │
│ → 吞吐量骤降 │
└─────────────────────────────────────┘
KCP 的拥塞控制 (可选! 可关闭!):
┌─────────────────────────────────────┐
│ │
│ 当 nc=1 时: │
│ │
│ cwnd │
│ ∞ |********************************│ ← 全速发送!
│ |********************************│ 不管网络拥不拥塞!
│ |********************************│
│ 0 +--------------------------------→ 时间
│ │
│ 代价: 可能抢占其他流的带宽 │
│ 收益: 极致的吞吐量和低延迟 │
│ │
│ 适用场景: │
│ - 专用链路 (专线/内网) │
│ - 愿意付费买更好带宽的场景 │
│ - 对实时性要求高于公平性的场景 │
└─────────────────────────────────────┘
关于关闭拥塞控制的道德提醒:
在公共互联网上关闭拥塞控制会导致你的流量”抢占”其他 TCP 流的带宽,这对其他用户不公平,甚至可能被运营商检测到并限速/封禁。
合理的做法是:在可控的网络环境中使用极速模式(如自建专线、企业内网),或在公网上使用平衡模式(nc=0)。
安全性:KCP 的安全层
KCP 原生不包含任何加密或认证机制!
这是一个非常重要的认知,很多人误以为”用了 KCP 就安全了”,其实不然。
KCP 本质上只解决"可靠传输",不解决"安全传输"
❌ 原始 KCP 的问题:
明文数据流:
[应用数据] → [KCP封装(序列号+校验)] → [UDP] → 网络
↑
任何人都能看到你的数据!
任何人都能伪造KCP包!
中间人可以篡改/注入/丢弃!
风险:
1. 窃听: 数据内容完全暴露 (如聊天记录、游戏指令)
2. 篡改: 攻击者修改数据包 (如修改游戏中的位置坐标)
3. 注入: 攻击者发送虚假包 (如伪造断开连接指令)
4. 重放: 攻击者捕获旧包重新发送 (如重复扣款操作)
解决方案:上层叠加加密层
✅ 正确的部署方式:
┌─────────────────────────────────────────────┐
│ 应用层 (Application) │
├─────────────────┬───────────────────────────┤
│ AES-256-GCM │ salsa20/poly1305 │ ← 加密层 (你来实现!)
│ ChaCha20-Poly │ 自定义加密方案 │
│ 或 DTLS 1.2 │ │
├─────────────────┴───────────────────────────┤
│ KCP (可靠传输层) │ ← 只负责可靠性
├─────────────────────────────────────────────┤
│ UDP (传输层) │
└─────────────────────────────────────────────┘
常见加密组合方案:
| 组合方式 | 使用场景 | 优点 | 缺点 |
|---|---|---|---|
| KCP + AES-256-CBC/GCM | 国内 VPN/加速器主流 | 成熟广泛,性能好 | 需要 PKI 密钥管理 |
| KCP + salsa20/poly1305 | 某些在线游戏 | 轻量,适合嵌入式 | 生态较小 |
| KCP + ChaCha20-Poly1305 | 移动端优化选择 | ARM 上性能优于 AES | 较新 |
| KCP + DTLS | 需要标准化的场景 | 有证书体系支持 | 开销较大,复杂度高 |
| KCP + 自定义对称加密 | 完全自主可控 | 灵活度最高 | 自己负责安全性审计 |
实战建议:如果你在使用 KCP 做产品,一定要在 KCP 层之下、UDP 层之上加一个加密层(或者 KCP 层之上也可以)。推荐使用成熟的加密库如 OpenSSL、libsodium 或 BoringSSL,不要自己实现加密算法。
FEC 前向纠错(可选扩展模块)
KCP 社区有 FEC(Forward Error Correction)扩展实现:
FEC 原理:
普通模式 (无FEC):
发送: [数据包1] [数据包2] [数据包3] [数据包4]
接收: [包1✅] [包2✅] [包3❌丢失!] [包4✅]
→ 需要请求重传包3 (增加一个 RTT 的延迟!)
FEC 模式:
发送: [数据包1] [数据包2] [数据包3] [数据包4] [冗余包R1]
(4个数据包 + 1个冗余包, 冗余率 25%)
接收: [包1✅] [包2✅] [包3❌丢失!] [包4✅] [R1✅]
→ 用 R1 通过数学运算恢复出包3! 无需重传! 延迟为0!
算法基础: Reed-Solomon 编码 (任意 N 个包中收到 M 个即可恢复全部)
代价:
- 增加带宽开销 (冗余率越高, 开销越大)
- 增加编码/解码的计算开销
- 适用于: 高丢包率且重传代价大的场景 (卫星链路、弱网环境)
注意:FEC 不是 KCP 核心库的一部分,而是社区扩展。GitHub 上搜索 “kcp fec” 可以找到多个开源实现。
性能基准数据
根据 KCP 作者 skywind3000 提供的测试数据:
| 性能指标 | TCP | KCP (nodelay 模式) | 提升 |
|---|---|---|---|
| 平均传输延迟 | 100%(基线) | ~65% | ↓ 降低 35% |
| 最大传输延迟 | 100%(基线) | ~10% | ↓ 降低 90% |
| 丢包恢复时间 | 200ms+(RTO) | < 30ms(快速重传) | 快 7x+ |
| 单连接吞吐量 | 受限于拥塞控制 | 可超过 TCP(关拥控时) | 看场景 |
延迟对比示意图:
TCP 延迟曲线:
| _
| | \_______
| | \________ 平均延迟较高
| |
| +--------------------→ 时间
| ↑抖动大, 最大延迟可达数百毫秒
KCP 延迟曲线:
| _ _ _
| | |||
| | |||______ 平均延迟低且稳定
| |
| +--------------------→ 时间
| ↑抖动小, 最大延迟被严格控制
客观提醒:以上为理想网络条件下的相对数据。实际效果因网络状况(丢包率、延迟、带宽)、KCP 参数配置、以及具体实现而异。建议在自己的真实环境中进行 benchmark 测试。
完整工作流程图
完整的 KCP 数据传输流程:
发送端(Sender) 接收端(Receiver)
| |
| [1] ikcp_send("Hello World") |
| → 数据存入 send_q |
| |
| [2] ikcp_update() 定时触发 flush |
| → send_q → snd_queue |
| → 封装 KCP 头部: |
| conv=连接标识 |
| cmd=IKCP_CMD_PUSH (数据包) |
| frg=分片编号 |
| wnd=可用窗口大小 |
| ts=时间戳 |
| sn=序列号 (递增) |
| una=期望收到的第一个未确认序号 |
| len=数据长度 |
| data="Hello World" |
| |
| [3] 通过 UDP 发送出去 |
| ======================================= UDP 网络 (可能丢包!) === |
| |
| [4] 接收到 KCP 包 |
| → 校验数据完整性 |
| → 根据 sn 判断是否有序 |
| → 有序: 直接入 rcv_queue |
| → 乱序: 存入 rcv_buf 等待后续排序 |
| → 生成 ACK (包含 una + 最新 sn) |
| |
| [5] 回复 ACK 包 (通过 UDP) |
| ======================================= UDP 网络 ====================== |
| |
| [6] 发送端收到 ACK |
| → 更新 snd_buf (移除已确认的包) |
| → 更新发送窗口 |
| → 如果发现有丢包 (通过 UNA/SACK 判断) |
| → 立即触发快速重传! (不等RTO) |
| |
| [7] 接收端应用层调用 ikcp_recv() |
| → 从 rcv_queue 按序取出完整数据 |
| → 返回 "Hello World" 给应用 |
| |
└──────────── 循环往复 ────────────┘
特殊情况处理:
[A] 丢包重传:
发了 [sn=5], 但没收到它的 ACK
→ 下次 update() 时检测到
→ 立即重传 [sn=5] (如果 resend > 0)
→ 即使 RTO 还没到!
[B] 乱序到达:
收到了 [sn=7], 但 [sn=6] 还没来
→ 把 [sn=7] 暂存在 rcv_buf
→ 等 [sn=6] 到达后一起按序交付给应用
[C] 重复包:
收到了 [sn=5], 但之前已经确认过了
→ 丢弃重复包 (不交付给应用)
→ 重传 ACK (防止对方不知道已经收到)
QUIC:Google 革新 → IETF 标准 → HTTP/3 的基石
术语说明:本文用户原始需求中提到的 “QUICK”,统一指代 QUIC(Quick UDP Internet Connections,RFC 9000)。这是 Google 提出、IETF 标准化的下一代传输协议,以下均使用标准名称 QUIC。
从 Google QUIC 到 IETF QUIC:发展时间线
QUIC 发展历程:
2012 Google 内部开始实验: "如果用 UDP + 自定义协议替代 TCP+TLS 会怎样?"
│
2013 Google 推出 gQUIC (基于 SPDY, Chrome 可启用)
│ - 目标: 减少 HTTPS 页面加载延迟
│ - 在 UDP 上实现了可靠加密传输
│
2015 gQUIC 流量占 Google 总流量约 7%
│
2016 IETF 成立 QUIC 工作组, 开始标准化
│ - 决定不兼容 gQUIC, 重新设计 (称为 iQUIC/IETF QUIC)
│ - TLS 1.3 作为唯一握手协议 (gQUIC 用的是自定义类似TLS的协议)
│
2018 IETF QUIC 草案陆续发布, 多个实现出现:
│ - quiche (Cloudflare, Rust)
│ - ngtcp2 (C/C++)
│ - aioquic (Python)
│ - MsQuic (Microsoft, C)
│
2021 ★ RFC 9000 / 9001 / 9002 正式发布!
│ QUIC 成为 IETF 国际标准
│
2022 HTTP/3 (RFC 9110 / 9114) 成为正式标准
│ QUIC 成为 HTTP/3 的底层传输协议
│
2024 主流浏览器全面支持:
│ Chrome / Edge (Chromium) ✅
│ Firefox ✅
│ Safari (iOS 17+/macOS 14+) ✅
└── 当前状态: 全球超过 30% 的 Web 流量使用 QUIC/HTTP/3
QUIC vs TCP + TLS:握手速度对比
这是 QUIC 最直观的优势,大幅减少连接建立的 RTT 次数。
┌─────────────────────────────────────────────────────────────────────┐
│ │
│ TCP + TLS 1.2 握手过程 (~3.5 RTT): │
│ │
│ Client Server │
│ | | │
│ |------- SYN ----------------------------------->| ① │
│ |<------ SYN + ACK ------------------------------| ② │
│ |------- ACK ----------------------------------->| ③ │
│ | [TCP 连接建立完成: 已过 1 RTT] | │
│ | | │
│ |------- ClientHello (TLS 握手) ---------------->| ④ │
│ |<------ ServerHello + Certificate -------------| ⑤ │
│ |------- KeyExchange + ChangeCipherSpec -------->| ⑥ │
│ |<------ NewSessionTicket + Finished -----------| ⑦ │
│ |------- Finished ----------------------------->| ⑧ │
│ | [TLS 握手完成: ~2 RTT] | │
│ | │ │
│ | ========= 开始传输应用数据 ========== │ │
│ |------- GET https://example.com -------------->| │
│ |<------ 200 OK (HTML) ------------------------| │
│ | │ │
│ 总计首字节时间: 1.5 RTT (TCP) + ~2 RTT (TLS) ≈ 3.5 RTT │
└─────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────┐
│ │
│ QUIC (IETF) 1-RTT 握手过程 (首次连接): │
│ │
│ Client Server │
│ | | │
│ |------- Initial 包 (Client Hello) ------------>| │
│ | 包含: TLS ClientHello + QUIC 参数 │ │
│ |<------ Initial + Handshake --------------------| │
│ | 包含: TLS ServerHello + Certificate │ │
│ | + Finished (加密握手完成) │ │
│ |------- Handshake (Finished) ----------------->| │
│ |<====== 1-RTT 加密密钥已建立 ======== │ │
│ |<------ 1-RTT 包 (加密的应用数据响应!) ----------| │
│ | │ │
│ | ========= 开始传输数据 (仅 1 RTT!) ========== │ │
│ |------- STREAM 数据 (如 HTTP GET) ------------> | │
│ |<------ STREAM 响应 (加密的 HTML) --------------| │
│ | │ │
│ 总计首字节时间: 1 RTT (!) │
│ 比 TCP+TLS 1.2 快了 3.5倍! │
└─────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────┐
│ │
│ QUIC 0-RTT 握手 (恢复之前的连接): │
│ │
│ Client Server │
│ | | │
│ |------- 0-RTT 包 (应用数据提前发送!) ---------->| │
│ | 包含: 之前缓存的参数 │ │
│ | + 应用层请求 (如 HTTP GET) │ │
│ | ⚠️ 注意: 此时还没完成握手验证! │ │
│ |<------ 1-RTT 包 (响应 + 新的 Session Ticket) --| │
│ | │ │
│ | ========= 0 RTT 即开始传数据! =========== │ │
│ | │ │
│ 总计首字节时间: ≈ 0 RTT (接近即时!) │
│ 条件: 客户端和服务端之前有过成功连接 │
└─────────────────────────────────────────────────────────────────────┘
总结对比:
┌─────────────────────┬──────────────┬────────────────┐
│ 协议组合 │ 握手所需 RTT │ 首字节时间 │
├─────────────────────┼──────────────┼────────────────┤
│ TCP + TLS 1.2 │ ~3.5 RTT │ ~3.5~4 往返 │
│ TCP + TLS 1.3 │ ~2.5 RTT │ ~2.5~3 往返 │
│ QUIC (首次连接) │ **1 RTT** │ **~1 往返** │
│ QUIC (恢复连接) │ **0 RTT** | **≈ 0 (客户端发送)** ⚠️ │
└─────────────────────┴──────────────┴────────────────┘
RTT 拆解说明(依据 RFC 793 / RFC 8446 / RFC 9000):
- TCP 三次握手 = 1.5 RTT(SYN → SYN+ACK → ACK)
- TLS 1.2 完整握手 = 2 RTT → TCP + TLS 1.2 合计 ~3.5 RTT
- TLS 1.3 完整握手 = 1 RTT → TCP + TLS 1.3 合计 ~2.5 RTT
- QUIC 首次连接:握手与加密合并,服务端可在首个响应包内直接返回数据 → ~1 RTT
- QUIC 恢复连接:客户端可立即发送请求(0-RTT),但服务端响应仍需约 1 RTT
核心特性一:TLS 1.3 内置加密(强制,不可关闭!)
QUIC 与 TCP + TLS 最本质的区别在于安全模型的设计位置不同:
┌─────────────────────────────┐ ┌─────────────────────────────┐
│ TCP + TLS 架构 │ │ QUIC 架构 │
├─────────────────────────────┤ ├─────────────────────────────┤
│ │ │ │
│ ┌───────────┐ ┌────────┐ │ │ ┌─────────────────────┐ │
│ │ 应用层数据 │→│ TLS层 │ │ │ │ 应用层数据 │ │
│ │ (HTTP等) │ │(可选!) │ │ │ └────────┬────────────┘ │
│ └───────────┘ └───┬────┘ │ │ │ 加密 │
│ │ │ │ ┌────────▼────────────┐ │
│ ┌──────────────────▼──┐ │ │ │ QUIC 层 (内置加密) │ │
│ │ TCP 层 │ │ │ │ TLS 1.3 是协议的一部分│ │
│ │ (明文头部!) │ │ │ │ 无法关闭! │ │
│ └──────────┬───────────┘ │ │ └────────┬────────────┘ │
│ │ │ │ │ 封装到UDP包 │
│ ┌──────────▼───────────┐ │ │ ┌───────▼────────────┐ │
│ │ IP 层 │ │ │ │ UDP 层 │ │
│ └──────────────────────┘ │ │ └─────────────────────┘ │
└─────────────────────────────┘ └─────────────────────────────┘
关键区别:
TCP + TLS:
- 加密是"外挂"的, 应用层决定是否使用
- TCP 头部 (序列号、ACK 等) 是明文的! ← 中间人可分析流量特征
- 可以不用 TLS (很多旧系统如此)
QUIC:
- 加密是"内置"的, 协议层面强制要求
- 几乎所有头部字段都加密! ← 端到端加密
- 只有 Connection ID 和部分包类型标识是明文
- 不存在"未加密的 QUIC"
QUIC 的加密范围
QUIC 包结构 (Long Header 示例):
明文部分 (所有网络设备可见):
┌──────┬──────┬──────┬──────────────────────┐
│Header│ Packet│ Vers │ Destination CID │ ← 路由需要这些信息
│ Form │ Type │ ion │ (Connection ID, 不可预测)│
└──────┴──────┴──────┴──────────────────────┘
加密部分 (只有端点能解密):
┌──────────────────────────────────────────────┐
│ Source CID │ Length │ Packet Number │ ← 大部分已加密
│ Token (可选) │ │ Payload (实际数据) │
└──────────────────────────────────────────────┘
↑
AEAD 加密 (AES-GCM 或 ChaCha20-Poly1305)
结果:
- 路由器只能看到: 这是一个 QUIC 包, 发给哪个 CID
- 路由器无法看到: 里面是什么数据, 发了多少个流, 序列号是什么
→ 有效防止深度包检测 (DPI) 和流量指纹识别
0-RTT 的安全隐患:重放攻击
0-RTT 允许客户端在握手完成前就发送数据,但这带来了一个风险:攻击者可以捕获并重放 0-RTT 数据。
攻击场景:
1. 用户向银行发送 0-RTT 请求: "转账100元给Alice"
2. 攻击者捕获了这个 0-RTT 包
3. 攻击者重发这个包
4. 银行服务器再次执行转账! → Alice 收到了双倍的钱
缓解措施 (RFC 9001 定义):
- 服务端只允许幂等操作使用 0-RTT(如 HTTP GET)
- 非 0-RTT 操作(POST/PUT)必须等待 1-RTT 握手完成
- 使用单次使用 Token(服务端发放的临时凭证,只能用一次)
- 缓存已处理的 0-RTT 数据去重
结论:0-RTT 很快但不是万能的,对于敏感操作仍需等待完整握手。
核心特性二:Stream 多路复用无队头阻塞
这是 QUIC 解决的另一个 TCP 固有痛点:
问题: HTTP/2 over TCP 的队头阻塞 (Head-of-Line Blocking)
TCP 连接 (1个):
┌──────────────────────────────────────────────────────┐
│ │
│ Stream 1: [GET /page.html] ........... [*丢包!*] ❌ │
│ Stream 2: [GET /style.css] ✅ 已到达! 但要等Stream1! │ ← 被阻塞!
│ Stream 3: [GET /image.png] ✅ 也到达了! 还是要等! │ ← 全堵了!
│ │
│ 原因: TCP 是字节流, 不区分逻辑边界 │
│ 一个包丢失 → 后续所有数据都无法交给应用层 │
│ (因为接收方无法确定后续字节的逻辑边界) │
│ │
└──────────────────────────────────────────────────────┘
QUIC 的解决方案: Stream 独立交付
QUIC 连接 (1个):
┌──────────────────────────────────────────────────────┐
│ │
│ Stream 1: [GET /page.html] ...... [*丢包!*] ❌ │
│ Stream 2: [GET /style.css] ✅ → 立即交付给应用! │ ← 不受影响!
│ Stream 3: [GET /image.png] ✅ → 也立即交付! │ ← 继续正常! │
│ │
│ 原因: 每个 Stream 有独立的序列号和 ACK 机制 │
│ Stream 1 丢了包只影响 Stream 1 │
│ Stream 2/3 完全独立, 各走各的 │
│ │
│ 类比: │
│ TCP 就像一条单车道公路 — 一辆车抛锚, 所有车都过不去 │
│ QUIC 就像多车道高速公路 — 一条道出事, 其他道照常通行 │
│ │
└──────────────────────────────────────────────────────┘
实测效果:在移动弱网环境下(丢包率 1%~2%),HTTP/2 over TCP 的页面加载时间可能比 HTTP/1.1 更慢(因为 HOL 阻塞放大了影响),而 QUIC (HTTP/3) 则始终稳定优于两者。
核心特性三:Connection ID 连接迁移
这是 QUIC 最具创新性的特性之一:
传统 TCP 连接的身份标识:
┌─────────────────────────────────────────────────┐
│ TCP 连接 = {源IP, 源端口, 目的IP, 目的端口} │
│ 即: 四元组 (4-Tuple) │
│ │
│ 场景: 手机用户浏览网页 │
│ │
│ WiFi 环境: │
│ 连接 = {192.168.1.100:54321 → 142.250.80.46:443}│
│ ↑ │
│ [用户走出咖啡厅, WiFi断开, 切换到 4G] │
│ │
│ 4G 环境: │
│ 新地址= {10.20.30.40:12345 → 142.250.80.46:443} │
│ ↑ 四元组变了! │
│ │
│ 结果: TCP 认为这是一个全新的连接! │
│ → 原连接失效! │
│ → 需要重新三次握手 + TLS握手! │
│ → 页面加载中断, 用户感知到卡顿/白屏 │
└─────────────────────────────────────────────────┘
QUIC 的解决方案: Connection ID (CID)
┌─────────────────────────────────────────────────┐
│ QUIC 连接标识 = 64位随机 Connection ID │
│ (与 IP/端口无关!) │
│ │
│ 场景: 同样是手机切换网络 │
│ │
│ WiFi 环境: │
│ CID = 0x8a3f9c2b1e4d7f00 │
│ 地址 = 192.168.1.100:54321 → 142.250.80.46:443 │
│ ↑ │
│ [用户走出咖啡厅, WiFi断开, 切换到 4G] │
│ │
│ 4G 环境: │
│ CID = 0x8a3f9c2b1e4d7f00 (没变!) │
│ 地址 = 10.20.30.40:12345 → 142.250.80.46:443 │
│ ↑ IP端口变了, 但 CID 相同! │
│ │
│ 结果: 服务端通过 CID 识别出是同一个连接! │
│ → 连接保持不断! ✅ │
│ → 页面继续加载, 用户无任何感知 │
│ → 正在下载的文件不会中断 │
│ → 视频通话不会掉线 │
└─────────────────────────────────────────────────┘
连接迁移的完整过程:
Client (手机) Server (CDN)
| |
|--- 通过 WiFi 正常通信 --- |
| CID=0xABC, Path #1 |
| |
| [检测到 WiFi 信号变弱] |
| [切换到 4G 网络] |
| |
|--- 使用 NEW_CONNECTION_ID + ------|
| Path Challenge (新路径探测) -->|
| (携带新的 CID, 通过 4G IP发出) |
| |
|<-- Path Response (确认新路径OK) ---|
| (证明: 你真的拥有这个新IP) |
| |
| [开始在新路径上发送数据] |
|--- STREAM data via 4G ----------->|
| |
| [旧的 WiFi 路径超时后自动关闭] |
| (不需要 TIME_WAIT!) |
为什么 Connection ID 能防劫持?
CID 是一个 64 位随机数,在握手中协商。即使攻击者知道了你的新 IP 地址,也无法伪造 QUIC 包,因为他不知道正确的 CID(而且大部分包内容还是加密的)。
协议阶段流转图
QUIC 连接生命周期:
Client Server
| |
| ══════════ 握手阶段 ══════════ |
| |
|----- Initial (Client Hello) ---------->│
| Long Header │
| 包含: TLS ClientHello │
| QUIC 参数 │
| |
|<---- Initial (可能带 Retry) -----------│
| 版本协商 / DoS 防护验证 │
| |
|----- Initial (带 Retry Token) -------->│
| |
|<---- Handshake (Server Hello+) --------│
| Long Header │
| 包含: TLS ServerHello │
| Certificate(s) │
| Finished (加密握手完毕) │
| |
|----- Handshake (Client Finished) ------>│
| Long Header │
| |
| ═════ 1-RTT 密钥已建立, 可以加密通信 ═════ │
| |
|<==== 1-RTT (Short Header) ==============│
| (可能是: 加密的响应数据 + Finished) │
| |
| ═════════ 数据传输阶段 ═══════════ │
| |
|===== Short Header STREAM 数据 ========>│
|<==== Short Header STREAM 数据 =========│
| (多个 Stream 并行传输, 无 HOL阻塞) │
| |
| ═════ 可选: 连接迁移 ═════ │
| |
| [网络环境变化: WiFi → 4G] │
| |
|===== NEW_CONNECTION_ID + Challenge ===>│ (新路径)
|<==== Path Response ===================│
| (迁移完成, 新路径生效) │
| |
| ═════════ 连接关闭 ═════════════ │
| |
|----- CONNECTION_CLOSE (Short Header) ->│
| (包含错误码和原因短语) │
| |
| [立即关闭, 无 TIME_WAIT!] │
| (因为是 UDP, 不占用四元组) │
| │
包类型速查:
┌────────────────────┬──────────┬──────────────────────────┐
│ 包类型 │ Header │ 说明 │
├────────────────────┼──────────┼──────────────────────────┤
│ Initial │ Long │ 握手启动, 必须回显Token │
│ 0-RTT │ Long │ 握手前提前发的数据 │
│ Handshake │ Long │ 加密握手参数交换 │
│ Retry │ Long │ 服务端验证客户端身份 │
│ 1-RTT │ Short │ 握手完成后加密的数据 │
│ (其他 Short) │ Short │ 正常应用数据帧 │
│ CONNECTION_CLOSE │ Short │ 关闭连接 │
└────────────────────┴──────────┴──────────────────────────┘
HTTP/3 与 QUIC 的关系
┌─────────────────────────────────────────────────────┐
│ HTTP/3 (应用层协议) │
│ RFC 9110 (语义) + RFC 9114 (映射到QUIC) │
│ │
│ 特性: │
│ ├── 语义与 HTTP/2 兼容 (方法/状态码/头部字段) │
│ ├── QPACK 头部压缩 (优化 HPACK, 解决队头阻塞) │
│ └── Server Push 支持 │
├─────────────────────────────────────────────────────┤
│ QUIC (传输层协议) │
│ RFC 9000 (核心) / RFC 9001 (TLS) / RFC 9002 (恢复) │
│ │
│ 特性: │
│ ├── Stream 多路复用 (无队头阻塞) │
│ ├── TLS 1.3 内置加密 (端到端) │
│ ├── Connection ID 连接迁移 │
│ ├── 0-RTT / 1-RTT 快速握手 │
│ └── 可插拔拥塞控制 (BBR/Cubic/NewReno) │
├─────────────────────────────────────────────────────┤
│ UDP (底层传输) │
│ RFC 768 │
│ │
│ 仅负责将数据报尽力送达 │
└─────────────────────────────────────────────────────┘
对应关系:
HTTP/1.1 → TCP
HTTP/2 → TCP + TLS
HTTP/3 → QUIC (内部自带 TLS 1.3, 底层用 UDP)
QPACK vs HPACK:
HTTP/2 用 HPACK 做头部压缩,但 HPACK 有一个问题,它依赖有序传输(in-order delivery),导致解压必须按序进行。这在 TCP 上没问题(反正也有 HOL),但在 QUIC 的多 Stream 模型下反而引入了新的阻塞点。
QPACK 解决了这个问题:允许各 Stream 独立解码自己的头部,彻底消除了压缩层面的队头阻塞。
用命令行测试 QUIC 连接
# ============================================
# 方法 1: 使用 curl 测试 QUIC/HTTP/3 连接
# ============================================
# curl 7.66+ 版本支持 --http3 选项
# 检查你的 curl 版本
curl --version | grep -i http3
# 如果没有输出, 说明当前版本不支持 HTTP/3
# 测试某个网站是否支持 QUIC/HTTP/3
curl --http3 -I --connect-timeout 5 https://www.google.com 2>&1 | head -10
# 成功支持 QUIC 时, 输出示例:
# HTTP/3 200
# content-type: text/html; charset=UTF-8
# alt-svc: h3=":443"; ma=2592000,h3-29=":443"; ma=2592000
# ^^^^^^^^^^^^
# 这个 alt-svc 头声明了 QUIC 支持!
# 不支持 QUIC 时会自动降级到 HTTP/1.1 或 HTTP/2:
curl --http3 -I --connect-timeout 5 https://www.example.com 2>&1 | head -5
# 可能输出: HTTP/2 400 (或自动降级警告)
# ============================================
# 方法 2: 使用 dig 查看 DNS HTTPS/SVC 记录
# ============================================
# HTTPS 记录 (RFC 9460) 告诉客户端目标站点支持的协议和参数
dig HTTPS www.google.com +short
# 输出示例:
# 1 . "h3-29=:443"; alpn=h3
# 解释: 支持 QUIC (h3-29), 端口 443, ALPN 协商名 h3
# SVCB 记录 (更详细的版本):
dig SVCB _https.www.google.com +short
# 输出示例:
# 1 . "h3-29=:443"; alpn=h3; ipv4hint=142.250.x.y
# ============================================
# 方法 3: 使用 openssl s_client 测试 TLS 1.3 握手
# ============================================
# QUIC 使用 TLS 1.3, 可以测试目标是否支持 TLS 1.3
openssl s_client -connect www.google.com:443 -tls1_3 </dev/null 2>/dev/null | grep "Protocol"
# 输出: Protocol : TLSv1.3
# 如果显示 TLSv1.2 或更低, 说明该服务器的 QUIC 配置可能有特殊处理
# ============================================
# 方法 4: 查看系统 QUIC 相关的网络配置
# ============================================
# Linux: 查看 UDP 缓冲区 (QUIC 基于 UDP, 受此限制)
sysctl net.core.rmem_max
sysctl net.core.wmem_max
# 建议: 高性能 QUIC 服务器应调大到 25MB+
sudo sysctl -w net.core.rmem_max=26214400
sudo sysctl -w net.core.wmem_max=26214400
# macOS: 查看相同参数
sysctl net.inet.udp.recvspace
sysctl net.udp.maxdgram
全面对比:谁才是你的最佳选择?
KCP vs TCP 详细对比(12 维度)
| # | 对比维度 | KCP | TCP | 优胜者 |
|---|---|---|---|---|
| 1 | 连接建立 | 无需握手,直接发送 | 三次握手(至少 1 RTT) | KCP |
| 2 | 首包延迟 | 接近 0 ms(无握手) | 至少 1.5 RTT ( | KCP |
| 3 | 平均传输延迟 | 低(快速重传,<30ms恢复) | 较高(等 RTO 或 3 个 dupACK,200ms+) | KCP |
| 4 | 最大传输延迟 | 远低于 TCP(约 TCP 的 1/10) | 可能很高(超时指数退避可达数秒) | KCP |
| 5 | 吞吐量 | 可更高(关闭拥塞控制时全速发送) | 受限于内核拥塞控制算法 | 看场景 |
| 6 | 丢包恢复速度 | 快(主动快速重传,不等超时) | 慢(RTO 通常 200ms+) | KCP |
| 7 | 公平性(拥塞控制) | 可完全关闭(可能抢占带宽) | 强制执行(保证网络公平性) | TCP |
| 8 | 安全性 | 原生无加密,需上层叠加 AES/salsa20 等 | 可选 TLS(成熟生态,一键启用) | TCP(更便捷) |
| 9 | 队头阻塞(HOL) | 单流模型,存在 HOL 阻塞 | 单字节流,存在 HOL 阻塞 | 平手 |
| 10 | 连接迁移 | 不支持(绑定四元组) | 不支持(绑定四元组) | 平手 |
| 11 | 部署兼容性 | 需集成 KCP SDK(C/C++/Go/Java 等多语言绑定) | OS 原生支持(所有操作系统内置) | TCP |
| 12 | 内核实现 | 用户空间库实现(应用层可控) | 内核协议栈(系统级优化,零拷贝等) | TCP |
| 13 | 生态成熟度 / 标准化 | 中高(国内广泛使用),但 无 RFC | 极高(40 年积累,RFC 793 系列) | TCP |
KCP vs TCP 结论:
选择 KCP 当你需要:
✅ 极致的低延迟 (游戏操作、音视频通话、实时交易)
✅ 自定义拥塞控制策略 (或完全关闭)
✅ 在弱网环境下更快的丢包恢复
✅ 应用层对传输过程的完整控制
继续使用 TCP 当你需要:
✅ 通用可靠传输 (文件下载、API 调用、数据库同步)
✅ 开箱即用的安全性 (TLS 一行配置)
✅ 全平台原生支持 (无需集成额外 SDK)
✅ 网络公平性 (不做"破坏者")
✅ 40 年沉淀的稳定性与生态
QUIC vs TCP (+ TLS) 详细对比(12 维度)
| # | 对比维度 | QUIC | TCP + TLS | 优胜者 |
|---|---|---|---|---|
| 1 | 握手 RTT | 1 RTT(首次)/ 0 RTT(复用) | QUIC | |
| 2 | 首字节时间 (TTFB) | ~1 RTT / ≈0(客户端发送) | QUIC | |
| 3 | 加密方式 | TLS 1.3 内置(协议层面强制) | TLS 外挂于应用层(可选) | QUIC |
| 4 | 安全模型 | 端到端加密(含大部分头部字段) | 仅加密载荷(TCP 头部明文) | QUIC |
| 5 | 多路复用 | Stream 多路复用,各 Stream 独立交付 | 单字节流(应用层自行分帧如 HTTP/2) | QUIC |
| 6 | 队头阻塞 | 无 HOL(各 Stream 独立 ACK) | 有 HOL(一个丢包阻塞全部) | QUIC |
| 7 | 连接迁移 | 支持(Connection ID 标识) | 不支持(四元组标识) | QUIC |
| 8 | 拥塞控制 | 可插拔(BBR/Cubic/NewReno,用户态配置) | 内核固定(需升级内核才能换算法) | QUIC |
| 9 | 丢包恢复机制 | 自定义 ACK/SACK/FEC(类似 TCP 但可优化) | 成熟(SACK/RACK/TLP,数十年打磨) | 平手(各有优势) |
| 10 | 安全性便利性 | 默认开启,无法关闭(开发者无需操心) | 需要显式配置 TLS(容易遗漏) | QUIC |
| 11 | 部署兼容性 | 需要 OS / 浏览器 / 库支持(老旧设备不支持) | 所有联网设备原生支持 | TCP |
| 12 | 连接结束开销 | 立即关闭(无 TIME_WAIT) | TIME_WAIT(等待 2MSL) | QUIC |
| 13 | 标准化程度 | 高(RFC 9000/9001/9002,HTTP/3 标准) | 极高(RFC 793 系列,互联网基石) | 平手(都是标准) |
QUIC vs TCP 结论:
选择 QUIC (HTTP/3) 当你需要:
✅ 最快的 Web 体验 (1RTT/0RTT 握手)
✅ 移动端无缝体验 (WiFi ↔ 4G 切换不掉线)
✅ 默认的安全 (不用操心 TLS 配置)
✅ 解决 HTTP/2 的队头阻塞问题
✅ 灵活的拥塞控制策略
继续使用 TCP(+TLS) 当你需要:
✅ 兼容所有设备 (包括 IoT 设备、旧版系统)
✅ 企业防火墙友好 (部分网络会阻断 UDP)
✅ 调试工具链成熟 (tcpdump/Wireshark 完美支持)
✅ 运维经验丰富 (40 年积累的排查体系)
综合适用场景矩阵
安全要求
低 ◄────────────────────► 高
┌───────────┬───────────┬───────────┬───────────┐
大 │ │ │ │ │
吞 │ UDT │ KCP │ KCP+AES │ QUIC │
量 │ (大数据) │ (低延迟) │(延迟+安全)│ (Web标准) │
↓ │ │ │ │ │
├────────────┼───────────┼───────────┼───────────┤
中 │ │ enet │ KCP │ QUIC │
等 │ TCP/RUDP │ (游戏轻量) │(音视频/ │ (HTTPS/ │
待 │ (通用/教学)│ RakNet │ 游戏/VPN) │ API) │
安 │ │ (Unity) │ │ │
全 │ │ │ │ │
↑ └───────────┴───────────┴───────────┴───────────┘
低 ◄────────────────────────────► 高
延迟要求
各方案一句话速查:
┌──────────┬──────────────────────────────────────────────────────────┐
│ TCP │ 通用可靠传输的默认选择 — 文件下载/API/数据库/邮件 │
│ KCP │ 延迟敏感型应用的首选 — 音视频/实时游戏/VPN加速器 │
│ QUIC │ Web 时代的未来标准 — HTTPS/HTTP3/WebSocket 替代方案 │
│ UDT │ 大规模数据传输 — 科学计算/地理信息/卫星数据/备份同步 │
│ enet │ 轻量级游戏网络层 — MOBA/FPS/独立游戏项目 │
│ RakNet │ Unity/虚幻引擎游戏的完整网络解决方案 │
│ RUDP │ 学习可靠传输原理的教学示例 — ARQ/GN/SW 协议入门 │
└──────────┴──────────────────────────────────────────────────────────┘
总结
今天我们系统梳理了从 UDP 协议本身 到 基于 UDP 的可靠传输方案 的完整知识体系:
UDP 协议本身:
- 仅 8 字节固定头部(源端口/目的端口/长度/校验和)
- 五大特性:无连接、不可靠、低开销、支持广播多播、面向报文
- 天然适用于 DNS/DHCP/NTP/VoIP/游戏等场景
- 但不可靠性限制了它的适用范围,催生了各种”可靠化”方案
六大可靠传输方案全景:
| 方案 | 一句话定位 | 最佳场景 | 安全性 |
|---|---|---|---|
| RUDP | ARQ 教学级实现 | 学习原理 | 无 |
| UDT | 大数据高速传输 | 海量数据跨网传输 | 可选 |
| KCP | 低延迟可靠传输 | 音视频/游戏/VPN | 需自建 |
| QUIC | 下一代 Web 传输标准 | HTTPS/Web API | 内置 TLS |
| enet | 游戏轻量网络库 | MOBA/FPS | 可选 AES |
| RakNet | 游戏完整网络框架 | Unity/UE 项目 | 插件 |
KCP 重点回顾:
- 设计哲学:以延迟换可靠性(vs TCP 以带宽换可靠性)
- 核心优势:ARQ 快速重传(不等超时)、nodelay 模式(可配 4 参数)、可关闭拥塞控制
- 性能提升:平均延迟降低约 35%,最大延迟降低约 90%
- 必须注意:KCP 原生不包含任何加密机制,生产环境务必在 KCP 之上叠加 AES/salsa20/ChaCha20 等加密层
- KCP 没有 RFC 规范,源自 skywind3000 的开源 GitHub 项目
QUIC 重点回顾:
- 发展历程:Google gQUIC (2013) → IETF 标准化 → RFC 9000 系列 (2021) → HTTP/3 (2022)
- 核心优势:1-RTT 握手(首次)/ 0-RTT 恢复(复用)
- TLS 1.3 内置强制加密(端到端,含头部字段)
- Stream 多路复用彻底消除队头阻塞
- Connection ID 支持连接迁移(WiFi ↔ 4G 无缝切换)
- 已成为 HTTP/3 (RFC 9114) 的底层传输协议,全球 30%+ Web 流量已采用
与 TCP 的关系,不会取代,而是互补:
| 场景 | 推荐选择 | 理由 |
|---|---|---|
| 通用 Web 服务 | TCP + TLS 或 QUIC/HTTP-3 | 新浏览器优先 QUIC,旧设备回退 TCP |
| 实时音视频/在线游戏 | KCP + 自建加密 | 延迟敏感是第一优先级 |
| 文件下载 / 大数据 | TCP 或 UTD | 吞吐量优先,长肥管道选 UDT |
| VPN / 网络加速器 | KCP + 加密 | 抗丢包能力 + 可关拥控 = 弱网利器 |
| 物联网 / 嵌入式 | TCP / CoAP over UDP | 资源受限,TCP 更省心 |
| 移动端 App(频繁切网) | QUIC | 连接迁移是杀手特性 |
最终建议:如果你在做一个新项目,先问自己三个问题:
- 延迟有多重要? → 很重要 → 考虑 KCP 或 QUIC
- 安全有多重要? → 很重要 → QUIC(自带 TLS)或 KCP+自建加密
- 需要兼容什么环境? → 只需现代浏览器 → QUIC;需全平台 → TCP;需自控客户端 → KCP
没有银弹。理解每个方案的 trade-off,才能做出最适合自己的技术决策。
参考资源
UDP 相关 RFC
- RFC 768 — User Datagram Protocol(UDP 协议标准定义,1980)
- RFC 1122 — Requirements for Internet Hosts(UDP 校验和细节说明)
QUIC 相关 RFC(IETF 国际标准)
- RFC 9000 — QUIC: A UDP-Based Multiplexed and Secure Transport(QUIC 核心协议规范)
- RFC 9001 — Using TLS to Authenticate QUIC(QUIC 与 TLS 1.3 的整合规范)
- RFC 9002 — QUIC Loss Detection and Congestion Control(QUIC 丢包检测与拥塞控制)
- RFC 9114 — HTTP/3(基于 QUIC 的 HTTP 语义映射)
TCP 相关 RFC(对比参考)
- RFC 793 — Transmission Control Protocol(TCP 协议标准)
- RFC 5681 — TCP Congestion Control(拥塞控制:慢启动/拥塞避免/快重传/快恢复)
- RFC 6298 — Computing TCP’s Retransmission Timer(RTO 计算规范)
- RFC 896 / RFC 1122 — Congestion Control in IP/TCP Interconnections(Nagle 算法 / TCP_NODELAY)
- RFC 1323 — TCP Extensions for High Performance(窗口缩放 / 时间戳 / PAWS)
- RFC 2018 — TCP Selective Acknowledgment Options(SACK 选择性确认)
- RFC 6928 — Increasing TCP’s Initial Window(初始拥塞窗口优化)
KCP 参考资料( 非官方 RFC 规范)
- skywind3000/kcp - GitHub — KCP 项目源码与技术 Wiki(协议设计文档、API 参考、性能测试)
- 作者博客文章:《KCP:一个快速可靠的 ARQ 协议》— 设计理念与核心特性说明
其他参考资料
- Wireshark 官方协议文档 — Wireshark: UDP / QUIC
- Cloudflare Blog — QUIC and HTTP/3 介绍系列
- Google Research Blog — The Evolution of QUIC
- Linux man pages — man 7 udp / man 7 tcp / man tcpdump
延伸阅读推荐 O3
- 《QUIC 协议详解》— 刘超(Cloudflare 中国),系统讲解 QUIC 协议细节
- 《高性能 Linux 网络编程,纵开、协程、全异步 I/O》— 游双刚,含 KCP 实战章节与应用案例
- IETF QUIC Working Group — https://datatracker.ietf.org/wg/quic/(最新草案与讨论)
- 《HTTP/3 从入门到精通》— 罗剑锋(Chromium 开发者视角)