QUIC(Quick UDP Internet Connections)是由 Google 设计并被 IETF 标准化的传输层协议,它基于 UDP 实现,但提供了类似 TCP 的可靠性和更高级的功能(如多路复用、0-RTT 握手、TLS 加密等)。
尽管 UDP 是不可靠的,QUIC 实现了自己的机制来提供:
✅ 可靠传输、顺序保证、流控、拥塞控制、加密通信
🚀 一句话理解:
QUIC 在 UDP 之上自己造了一个“更好的 TCP”,通过用户态实现可靠传输。
🧩 QUIC 如何在 UDP 上实现可靠传输?
下面是 QUIC 提供可靠性的核心机制:
✅ 1. 数据分片与多路复用(Streams)
QUIC 使用 Stream 概念将数据拆分成多个逻辑流,每个流有自己的 ID 和顺序控制。
每个数据包中可能包含多个流的数据片段。
每个 Stream 保持自己的有序性和重传机制,互不影响,解决了 TCP 的“队头阻塞(Head-of-line blocking)”问题。
✅ 2. ACK 机制与重传
每个 QUIC 包都有一个唯一的包序号(Packet Number)。
接收方会通过 ACK frame 显式告诉发送方收到了哪些包(可能是一个范围段,例如
ACK [5,6,7,9]
)。发送方根据 ACK 结果进行 选择性重传(Selective Retransmission),而不是像 TCP 那样使用窗口回退(Go-Back-N)。
✅ 3. 流控(Flow Control)
QUIC 实现了两级流控:
类型 | 控制内容 |
---|---|
连接级流控 | 控制整个连接中所有数据的大小 |
流级流控 | 控制单个 Stream 可发送的字节量 |
避免发送方淹没接收方,防止内存爆炸。
QUIC 实现流控(Flow Control)是为了防止发送方发送太多数据而压垮接收方的内存,确保 发送速度与接收能力匹配。
QUIC 的流控机制比 TCP 更灵活,它支持:
连接级流控(Connection-level) + 流级流控(Stream-level)
✅ 一句话总结:
QUIC 使用
MAX_DATA
和MAX_STREAM_DATA
帧,让接收方“显式告诉”发送方它还能接受多少数据,从而实现精细的流控。
🔍 QUIC 的两个流控层次
类型 | 控制范围 | 控制方式 |
---|---|---|
连接级流控 | 控制整个连接总共能发多少数据 | 使用 MAX_DATA 帧通知 |
流级(单条流)流控 | 控制某条 stream 能发多少数据 | 使用 MAX_STREAM_DATA 帧通知 |
🧩 工作机制详解
1. 🚦 初始窗口(Initial Flow Control Window)
每当连接或某个 stream 建立时,接收方通过
Transport Parameters
告诉发送方:initial_max_data = 65536 # 整个连接最多能发 64KB initial_max_stream_data = 32768 # 每个 stream 最多能发 32KB
2. 📤 发送方:按窗口大小发数据
每个 packet 中的数据都有位置偏移(offset)
发送方不能发送超过
offset > max_data
的内容如果快达到限制,就暂停发送,等接收方“放行”
3. 📥 接收方:接收 + 消费数据后,发送 MAX_*
帧
当接收方:
消费了部分数据(应用层读取了),或者
有更多缓冲空间
就会发以下帧通知发送方放宽限制:
帧类型 | 作用 |
---|---|
MAX_DATA |
提高连接级可发送总量 |
MAX_STREAM_DATA |
提高某个 stream 的可发送数据量 |
📝 例子:
MAX_STREAM_DATA(StreamID=5, MaximumData=64000)
MAX_DATA(MaximumData=128000)
4. 🚧 如果发送方超过限制会怎样?
接收方会直接 丢弃该数据包
并可能发送
FLOW_CONTROL_ERROR
帧,强制断开连接
🔁 动态调整窗口(流控窗口增长)
QUIC 支持动态调整窗口大小,类似 TCP 的“滑动窗口”机制,但更灵活:
接收方可以基于自身处理速度、缓冲区情况等策略动态调整
应用层可参与窗口策略调整(QUIC 是用户态协议)
📊 示例图:QUIC 流控流程简图
[Sender] [Receiver]
│ │
│───── Data (offset: 0~32767) ─────▶│ ✅ 在窗口范围内
│───── Data (offset: 32768~65535) ─▶│ ❌ 超出流窗口限制
│ │
│◀───── MAX_STREAM_DATA (64000) ────│ ✅ 允许再发更多
✅ 总结:QUIC 的流控机制比 TCP 更灵活的地方
特性 | TCP | QUIC |
---|---|---|
支持多路复用下的流控 | ❌ 需应用层实现 | ✅ 原生支持 per-stream 流控 |
流控信息粒度 | 每个连接一组窗口 | 每个流都有单独窗口 |
流控窗口通告方式 | 被动通告(ACK + 窗口值) | 主动通告(MAX_* 帧) |
动态扩展 | 有,但实现不易 | 简洁灵活,用户态易扩展 |
✅ 4. 拥塞控制(Congestion Control)
QUIC 可复用 TCP 的拥塞控制算法(如 Reno、CUBIC、BBR 等)。
因为 QUIC 完全在用户态,所以可以快速升级/切换拥塞算法,而不需要内核修改。
✅ 5. 加密与握手(TLS 1.3)
🧵 四、多路复用避免队头阻塞,加速整体数据流
TCP 中多个逻辑流复用一个连接时,某个小包丢失可能导致整个流被阻塞(队头阻塞)。
QUIC 的解决方式:
📶 五、QUIC 支持连接迁移,减少断线重连时间
🔚 小结一句话:
QUIC + UDP 快的根本原因在于它跳过了 TCP 的繁琐握手、内核开销和流阻塞,通过用户态协议 + 0-RTT 加密通信让“发第一个字节”变得更快。
✅ 总结对比表
项目 | TCP + TLS | QUIC + UDP |
---|---|---|
握手延迟 | 至少 1~2 RTT | 最快 0-RTT,首次仅需 1 RTT |
加密 | TLS 分层 | 内建 TLS 1.3,第一包就加密 |
队头阻塞 | 存在 | 消除(Stream 级别传输) |
连接状态 | 内核态管理 | 用户态管理,效率高 |
多路复用 | 需要上层协议实现 | 协议原生支持 |
连接迁移 | 不支持 | 原生支持 Connection ID 迁移 |
适合移动网络 | 一般 | 非常适合(连接迁移 + 0-RTT) |
所有 QUIC 数据包(除了第一个)都是 强加密 的。
基于 TLS 1.3 实现握手和密钥协商,合并传输和加密握手,支持 0-RTT 和 1-RTT 连接建立。
避免了 TCP + TLS 的多轮握手,提高首次连接速度。
🔍 详细原因分析(按阶段分解)
🟡 一、TCP + TLS 的握手流程 = 至少 3 次往返
传统的 TCP 连接建立 + TLS 加密握手如下:
1. TCP 三次握手(1.5 RTT): Client → SYN Server → SYN-ACK Client → ACK 2. TLS 1.2(或 1.3)握手(再来 1~2 RTT) 3. 才能发送加密数据
即:首次连接至少耗时 1~2 RTT(往返时间)
🟢 二、QUIC 将 握手和加密合并在一次往返中
QUIC 的握手流程使用 TLS 1.3 直接集成在传输协议中:
首次连接(1-RTT):
Client → Initial Packet(携带 TLS Client Hello) ← 第一次发包就带加密握手 ← Server Hello + 加密信息(+ 证书等) Client → Finished(+ 应用数据)
重连(0-RTT):
Client → 数据 + 加密握手(直接发数据!) ← ★ 零延迟
👉 QUIC 可以实现 “0-RTT 数据传输”,几乎是立即发送第一条消息。
🔧 三、UDP 不需要内核状态建立连接,QUIC 在用户态实现更灵活
TCP 是 面向连接的:需要在内核里维护连接状态(socket 状态机)。
UDP 是无连接协议,QUIC 在用户态自己管理连接状态,避免了内核/用户态频繁切换。
用户态连接管理允许更快的上下文切换、更容易多路复用。
每个 stream 有独立的传输/重传机制
某一 stream 丢包不会阻塞其他流,数据能更快抵达
QUIC 连接绑定在 Connection ID,而不是 IP + Port
移动设备换网(如从 Wi-Fi 切 4G)时无需重新建立连接,延迟更小
✅ 6. 包编号与重排重组
QUIC 的包编号是严格递增的,不可重用。
即使包乱序到达,也可通过包号重排序。
QUIC 自己实现了类似 TCP 的
SACK(Selective ACK)
功能。
✅ 7. 头部校验和加密保护
包头也经过加密处理,防止中间人攻击(如修改流量控制字段等)。
📦 总结:QUIC 如何在 UDP 上“可靠传输”
技术点 | 实现作用 |
---|---|
Stream(多路复用) | 消除队头阻塞、实现数据隔离 |
Packet Number + ACK | 保证数据到达与丢包检测 |
重传机制 | 实现可靠交付 |
流控 + 拥塞控制 | 限制数据发送速度,防止拥堵 |
TLS1.3 加密 | 确保安全性和身份验证 |
用户态实现 | 更灵活,可快速迭代 |
📌 简图:QUIC vs TCP(在可靠性层面)
┌──────────────┐ ┌──────────────┐
│ 应用层 │ │ 应用层 │
└────┬──────▲──┘ └────┬──────▲──┘
▼ │ ▼ │
┌──────────────┐ ┌──────────────┐
│ QUIC 协议 │ │ TCP 协议 │
└────┬──────▲──┘ └────┬──────▲──┘
▼ │ ▼ │
┌──────────────┐ ┌──────────────┐
│ UDP/IP │ │ IP层 │
└──────────────┘ └──────────────┘
QUIC + UDP 连接更快,是因为它在 连接建立阶段(握手)和数据传输机制方面做了大量优化,特别针对 TCP 的延迟瓶颈进行了设计改进。
✅ 简要结论:
QUIC 比 TCP 快,主要因为它省掉了握手轮次 + 消除了 TCP+TLS 分层带来的延迟 + 更高效的连接复用。