QUIC (Quick UDP Internet Connections) 是由 Google 设计、后经 IETF 标准化的下一代传输层协议。(因此有gQUIC和IETF QUIC两个版本)它是 HTTP/3 的底层核心,旨在替代传统的 “TCP + TLS” 组合,让互联网传输更快、更安全、更稳定。

Quic相关电子书网站:简体中文 | HTTP/3 explained QUIC rfc文档:RFC 9000: QUIC: A UDP-Based Multiplexed and Secure Transport

QUIC基础概念

1. Packet(数据包):物理运输单位

Packet 是 QUIC 在网络上传输的最小单位,它被封装在 UDP 报文的 Payload(净荷)中。

  • 它的职责:
    • 封装与加密:Packet 拥有报文头(Header),负责标识连接 ID(CID)、版本号和包序号(Packet Number)。它是 QUIC 加密的边界,整个 Packet(除极少数头部字段)都是加密的。
    • 确认与重传:QUIC 的丢包检测和拥塞控制是基于 Packet 的。每发一个 Packet,它的序列号(Packet Number)就加 1。如果对方没收到,重传的是 Packet 里的内容,但会装进一个新的 Packet(新序号)里。
  • 层级关系:一个 UDP 包里可以塞一个或多个 QUIC Packet。

2. Stream(流):逻辑业务单位

Stream 是应用层看到的数据通道。在 QUIC 连接中,你可以同时开启成百上千个 Stream。

  • 它的职责:
    • 多路复用:这是 QUIC 解决队头阻塞的关键。Stream 之间是相互独立的。Stream 1 丢了包,Stream 2 照样走,不会因为木材没到就耽误钢铁卸货。
    • 有序性:虽然 Packet 到达可能乱序,但同一个 Stream 内部的数据必须是有序的。QUIC 会根据 Offset(偏移量)在接收端把数据拼好交给应用层。
    • 流量控制:Stream 级别有自己的窗口限制,防止某个 Stream 消耗掉所有内存。
  • 层级关系:Stream 是一个虚拟概念,它的数据会被拆分成许多块,塞进不同的 Frame 里。

3. Frame(帧):功能指令单位

Frame 是 Packet 内部的最小功能单元。一个 Packet 的 Payload(有效载荷)部分是由一个或多个 Frame 组成的。

  • 它的职责:
    • 具体的动作:有的 Frame 负责运数据(STREAM Frame),有的负责签收确认(ACK Frame),有的负责报错(CONNECTION_CLOSE Frame)。
    • 混合装载:一个 Packet(车厢)里可以同时装:
      • 来自 Stream 1 的一段数据(STREAM Frame)
      • 来自 Stream 4 的一段数据(STREAM Frame)
      • 对之前收到的包的确认信息(ACK Frame)
  • 层级关系:Frame 存在于 Packet 之中。

一个典型的交互场景:

  1. 应用层:我想发一张图片(开启 Stream 5)。
  2. QUIC 协议层:把图片数据切成 3 块,每块打成一个 STREAM Frame。
  3. 打包:把第一个 Frame 塞进 Packet 1,把第二个 Frame 塞进 Packet 2…(同时可能往 Packet 1 里顺便塞一个 ACK Frame 确认对方的消息)。
  4. 传输:将 Packet 封装进 UDP 发走。
  5. 接收:对方收到 UDP 包,解密 Packet,拆出 Frame。如果是 STREAM Frame,就根据里面的 Stream ID 5 和 Offset 还原出图片。

为什么要发明 QUIC?(解决 TCP 的痛点)

在 QUIC 出现之前,网页加载主要靠 TCP + TLS。但随着移动互联网的发展,这套组合显露出了三大弊端:

  1. 建立连接太慢(高延迟):
    • TCP 需要 3 次握手,TLS 还需要 1-2 次握手。在发送数据前,双方得来回跑 2-3 个往返(RTT)。在弱网下,这会导致明显的转圈等待。
  2. 队头阻塞(Head-of-Line Blocking):
    • 虽然 HTTP/2 可以在一个 TCP 连接上同时发多个文件,但 TCP 本质是一个“单通道”有序流。如果其中一个数据包丢了,TCP 会停下来等待重传,导致后续所有文件都堵在后面,即使它们已经到达了。
  3. 网络切换容易断开:
    • TCP 依靠“四元组”(源IP、源端口、目的IP、目的端口)识别连接。当你从 Wi-Fi 切换到 4G 时,IP 变了,TCP 连接必须断开重连。

QUIC 是如何运作的?

QUIC 在 UDP 之上自己实现了一套可靠传输机制(确认应答、重传、拥塞控制),并把 TLS 1.3 直接集成进去。

QUIC 的四大核心特性:

1. 极速握手 (0-RTT / 1-RTT)

QUIC提供0-RTT和1-RTT的连接建立,这意味着QUIC在最佳情况下不需要任何的额外往返时间便可建立新连接。其中更快的0-RTT仅在两个主机之间建立过连接且缓存了该连接的“秘密”(secret)时可以使用。

  • 1-RTT:在 TCP 中,建立加密连接需要 TCP 3次握手 + TLS 1.3 握手(总计 2-3 个 RTT)。QUIC 将两者合二为一:客户端在发送第一个 UDP 包(Initial)时,就把 TLS 的 ClientHello 塞进去。服务器回一个包就完成了密钥交换。一次往返即可开始传数据。
  • 0-RTT:如果客户端之前访问过该服务器,可以缓存服务器的“门票”(Session Ticket)。下次连接时,客户端在第一个包里直接带上加密的应用数据。真正实现“零延迟”发数据。

2. 彻底解决队头阻塞

  • 类似SCTP、SSH和HTTP/2,QUIC在同一物理连接上可以有多个独立的逻辑数据流。这些数据流并行在同一个连接上传输,不影响其他流。
  • 不同流之间是相互独立的。QUIC的单个数据流可以保证有序交付,但多个数据流之间可能乱序。这意味着单个数据流的传输是按序的,但是多个数据流中接收方收到的顺序可能与发送方的发送顺序不同!
    • 如果流 A 的包丢了,只会阻塞流 A,流 B 和流 C 的传输完全不受影响。这彻底解决了 HTTP/2 在 TCP 上的顽疾。

3. 连接迁移 (Connection Migration)

  • QUIC 不再使用 IP/端口来识别连接,而是使用一个 64 位的 Connection ID (CID)。
  • 场景: 当你拿着手机从电梯出来,Wi-Fi 自动切到 5G,虽然你的 IP 变了,但只要 CID 没变,QUIC 连接就能无缝继续,你刷的视频不会卡顿,也不需要重新登录。

4. 强制内置加密

  • 在 TCP 时代,TLS 加密是可选的“插件”。
  • 在 QUIC 中,TLS 1.3 是强制内置的。不仅用户数据是加密的,连协议本身的元数据(比如包序号)也被大部分加密,这防止了网络中间设备(如运营商路由器)对协议进行篡改或窥探。

QUIC vs TCP 形象对比

特性TCP + TLS (HTTP/2)QUIC (HTTP/3)
基础协议基于 IP 的 TCP基于 IP 的 UDP
握手耗时2-3 个 RTT0-1 个 RTT
多路复用有队头阻塞(一人丢包,全家停步)无队头阻塞(一人丢包,他人照跑)
移动性切网络必断,需重连切网络不断,无缝迁移
安全性外部插件,握手分开原生集成 TLS 1.3,安全性更高

为什么要基于UDP而不是新创造一个协议

因为在互联网上部署遭遇很大的困难,创造新型传输层协议的努力基本上都失败了。用户与服务器之间要经过许多防火墙、NAT(地址转换)、路由器和其他中间设备(middle-box),这些设备有很多只认TCP和UDP。如果使用另一种传输层协议,那么就会有N%的连接无法建立,这些中间设备会认为除TCP和UDP协议以外的协议都是不安全或者有问题的。如此高的的失败率一般被认为不值得再做出努力。 另外,网络栈中的传输层协议改动一般意味着操作系统内核也要做出修改。更新和部署新款操作系统内核的过程十分缓慢,需要付出很大的努力。由IETF标准化的许多TCP新特性都因缺乏广泛支持而没有得到广泛的部署或使用。


传输层与应用层协议

IETF版QUIC是一个传输层协议,在该协议之上可以运行其他应用层协议。初始的应用层协议是HTTP/3(h3)。

传输层协议负责连接和数据流处理。

在Google的传统QUIC中,传输层与HTTP融在一起,为包揽一切的全功能设计,它是一个更有指向性的“基于UDP传输HTTP/2帧”(send-http/2-frames-over-udp)的协议。


QUIC报文解析

QUIC 报文分为两大类:长报文头 (Long Header) 和 短报文头 (Short Header)。

1. 长报文头 (Long Header) —— 建立连接专用

长报文头在连接还没完全建立好、或者需要版本协商时使用。

字段名称长度用途说明
Header Form1 bit固定为 1,标识这是一个长报文头。
Fixed Bit1 bit固定为 1,用于防范某些针对协议的攻击,帮助识别 QUIC 流量。
Long Packet Type2 bits报文子类型:00 Initial(初始), 01 0-RTT, 10 Handshake(握手), 11 Retry(重试)。
Type-Specific Bits4 bits随类型变化。例如在 Initial 报文中,包含 Packet Number 的长度。
Version32 bitsQUIC 版本号。例如 0x00000001 表示 RFC 9000 标准版。
DCID Length8 bits目标连接 ID (Destination Connection ID) 的长度。
DCID0-160 bits核心字段:目标连接 ID。用于在路由切换时标识同一个连接。
SCID Length8 bits源连接 ID (Source Connection ID) 的长度。
SCID0-160 bits源连接 ID。
Type-Specific Fields可变例如 Initial 报文会有 Token(用于防范地址伪造攻击)。
Length可变长整数标识该报文剩余部分的字节数(包括 Packet Number 和 Payload)。
Packet Number8-32 bits报文序列号。注意:在传输时是被加密的,防止中间设备监听。
Payload (Frames)可变真正的数据。由一个或多个 Frame(帧) 组成。
长报文头中有一个明确的 Length 字段。
  • 作用:这个 Length 字段指明了该 QUIC 报文剩余部分(即 Packet Number + Payload)的字节数。
  • 为什么要显式指明长度? 因为 QUIC 支持报文合并 (Coalescing)。在一个 UDP 数据包中,可以顺序存放多个 QUIC 报文(例如:一个 Initial 报文后面紧跟一个 Handshake 报文)。有了 Length 字段,解析器才知道第一个报文在哪里结束,第二个报文从哪里开始。

2. 短报文头 (Short Header) —— 数据传输专用

连接建立后的常规数据包,为了极致的带宽利用率,去掉了版本、SCID 等冗余信息。

字段名称长度用途说明
Header Form1 bit固定为 0,标识这是一个短报文头。
Fixed Bit1 bit固定为 1。
Spin Bit1 bit旋转位:用于测量 RTT。客户端和服务器轮流翻转它,中间设备通过观察翻转周期即可知道延迟。
Reserved Bits2 bits预留,必须为 0。
Key Phase1 bit密钥相位:用于切换加密密钥,实现密钥的滚动更新。
Packet Number Len2 bits标识随后的 Packet Number 占用几个字节(1, 2, 或 4 字节)。
DCID可变目标连接 ID。
Packet Number8-32 bits加密的报文序列号。
Payload (Frames)可变加密的帧数据。
短报文头中没有 Length 字段。
  • 作用:短报文头通常是 UDP 数据包中的最后一个(或唯一一个)报文。
  • 如何计算长度:其长度由 UDP 报文的总长度 减去 当前位置之前的偏移量 得到。即:报文长度 = UDP净荷长度 - 短报文起始位置。

3. 报文内部:Frame(帧)的结构

QUIC 报文的 Payload 部分由多个 Frame 组成。常见的有:

STREAM Frame(应用数据帧)

这是最频繁出现的帧,用于承载 HTTP/3 或其他应用层数据。

字段名称长度作用说明
Type1 byte范围 0x08 - 0x0F。低 3 位是标志位:OFF(是否有偏移量)、LEN(是否有长度字段)、FIN(是否是流的终点)。
Stream ID可变长整数标识数据属于哪个流(如某个图片请求)。
Offset可变长整数(可选) 该数据在流中的起始位置。用于处理流乱序到达,重组数据。
Length可变长整数(可选) Data 字段的长度。
Stream Data剩余部分实际的应用层字节流。
  • 设计精妙处:如果一个报文里只有一个 Stream Frame,Length 可以省略,解析器直接读到包末尾,节省字节。

ACK Frame(确认应答帧)

QUIC 不使用 TCP 的累积确认,而是使用这种高度精简的 Frame 告知发送方收到了哪些包。

字段名称长度作用说明
Type1 byte0x02 或 0x03(取决于是否有 ECN 网络拥塞标记)。
Largest Acked可变长整数接收方目前收到的最大 Packet Number。
Ack Delay可变长整数接收方收到包到发送 ACK 之间故意等待的时间(用于更精准计算 RTT)。
Ack Range Count可变长整数表示后面有多少个非连续的确认范围。
First Ack Range可变长整数表示从 Largest Acked 往下数,连续确认了多少个包。
Gap & Range可变长整数(重复字段) 用于描述中间“丢包”造成的空洞。
  • 设计精妙处:通过 Gap 和 Range 的组合,一个 ACK Frame 就能表达出“我收到了1-10和15-20,但没收到11-14”,极大提高了处理丢包的效率。

CRYPTO Frame(加密握手帧)

专门用于承载 TLS 握手数据。

字段名称长度作用说明
Type1 byte固定为 0x06。
Offset可变长整数握手数据的偏移量。
Length可变长整数握手数据的长度。
Crypto Data剩余部分实际的 TLS 记录(如 ClientHello)。
  • 区别:它和 STREAM Frame 很像,但没有 Stream ID,因为握手数据被视为一个全局的单一流。

CONNECTION_CLOSE Frame(连接关闭帧)

当发生协议错误或主动断开连接时使用。

字段名称长度作用说明
Type1 byte0x1c(QUIC层错误)或 0x1d(应用层错误)。
Error Code可变长整数错误代码(如 NO_ERROR, PROTOCOL_VIOLATION)。
Frame Type可变长整数触发错误的那个帧的类型(仅限 0x1c 类型)。
Reason Phrase Len可变长整数错误原因文本字符串的长度。
Reason Phrase可变可读的错误描述字符串。

NEW_CONNECTION_ID Frame(连接迁移核心帧)

这是实现“Wi-Fi 切 4G 不掉线”的关键。

字段名称长度作用说明
Type1 byte固定为 0x18。
Sequence Number可变长整数这个 ID 的序号。
Retire Prior To可变长整数要求对方停止使用比此序号小的旧 ID。
Length1 byte新 CID 的长度。
Connection ID可变服务器分发给客户端的新 ID,用于后续路径切换。
Stateless Reset Token16 bytes即使服务器崩溃,也能凭此 Token 识别并重置连接。

PADDING(填充帧)

PADDING (0x00):全 0 填充。用于将初始报文凑齐 1200 字节(MTU 探测,防止放大攻击)。

什么是放大攻击 (Amplification Attack)?

  1. UDP 的特性:UDP 是无连接的,发送端可以轻易伪造“源 IP 地址”。TCP由于需要三次握手确认连接,就不会受到放大攻击。
  2. 攻击原理:
    • 攻击者 向一个 服务器 发送一个非常小的请求(例如 10 字节),但把数据包里的“源 IP”改成 受害者 的 IP。
    • 服务器 收到请求后,如果返回一个非常大的响应(例如 1000 字节)。
    • 结果:受害者并没发请求,却收到了巨大的流量。攻击者利用服务器的响应,将流量“放大”了 100 倍。
  3. QUIC 的风险:在 QUIC 握手初期,客户端发一个 Initial 报文(ClientHello),服务器会返回证书等大量信息。如果不加限制,QUIC 就会变成一个完美的放大攻击工具。

为了解决上述问题,QUIC 协议(RFC 9000)强制规定:所有 Initial 报文(初始握手报文)的 UDP 净荷长度必须至少为 1200 字节。

如果你的实际数据(握手信息)没那么大,就必须用 PADDING 帧 填满。

PADDING 的作用:

  1. 限制放大倍数 (Anti-Amplification):
    • 服务器在验证客户端 IP 真实性之前,发送的数据量不能超过接收数据量的 3 倍。
    • 如果客户端发了一个 1200 字节的包(含 PADDING),服务器就可以合法地回传最多 3600 字节。
    • 这迫使攻击者如果想发起攻击,自己也得耗费同样巨大的带宽,攻击者的“杠杆”消失了,攻击也就失去了意义。
  2. 路径 MTU 探测 (MTU Discovery):
    • 互联网路径上最小的 MTU(最大传输单元)通常是 1280 字节(IPv6 的最低要求)。
    • 如果一个 1200 字节的 QUIC 包(含 PADDING)能安全到达服务器,说明这条路径支持大气泡传输。
    • 如果发不出去,QUIC 会立刻发现网络环境有问题,从而避免了后续大数据包频繁被分片或丢弃。

其他常用控制帧 (简述)

  • PING (0x01):保持连接活跃,探测路径可达性。
  • RESET_STREAM (0x04):发送方通知接收方:“我不发这个流了,你可以把它丢掉”。
  • MAX_DATA (0x10):连接级流量控制,告诉对方:“你在这个连接里总共只能发这么多字节”。
  • MAX_STREAM_DATA (0x11):流级流量控制。
  • PATH_CHALLENGE (0x1a):连接迁移时发出的“挑战包”,包含 8 字节随机数。
  • PATH_RESPONSE (0x1b):对方回显随机数,证明新路径确实通畅。

可变长度字段的判断原理

QUIC 几乎所有涉及“长度”和“数值”的字段(如 Length, Stream Offset, Stream ID 等)都使用了一种精巧的可变长度整数编码 (Variable-Length Integer Encoding)。

前 2 位标识法

任何一个可变长度的整数,它的前 2 个 bit(最高有效位)决定了整个数值占用多少个字节:

前 2 位 (Binary)剩余长度总字节数取值范围
000 字节1 字节0 到 63 ()
011 字节2 字节0 到 16,383 ()
103 字节4 字节0 到 1,073,741,823 ()
117 字节8 字节0 到

解析流程示例: 当解析器读到一个字节,先看前 2 位。如果是 01,解析器就知道“哦,这还没完,我得再读 1 个字节”,然后把这 2 个字节合并,去掉前 2 位标识位,剩下的 14 位就是真实的数值。

特殊可变长字段

除了通用的整数编码,还有几个关键字段有特殊的判断方式:

1. Connection ID (CID) 的长度

  • 在长报文头中:有专门的 DCID Len 和 SCID Len 字段(各占 1 字节)。解析器先读这 1 字节的长度,再根据长度读取后续的 ID。
  • 在短报文头中:短报文头里没有长度字段。解析器必须依靠“上下文”知道 CID 的长度。
    • 原理:在握手阶段,双方会协商好 CID 的长度。当连接进入数据传输阶段(使用短报文)时,解析器查一下本地保存的该连接的状态,就知道该读多少字节了。

2. Packet Number (PN) 的长度

Packet Number 的长度是动态变化的(为了节省带宽,1 到 4 字节不等)。

  • 判断方法:它隐藏在报文头的第一个字节(Type Byte)中。
  • 具体规则:第一个字节的最后 2 位(bits 6-7)决定了 PN 的长度。
    • 00 → 1 字节
    • 01 → 2 字节
    • 10 → 3 字节
    • 11 → 4 字节
  • 注意:由于 PN 头是加密的,解析器必须先根据之前交换的密钥对头进行“去掩码”处理,才能读到这两位。

3. Stream Frame 中的数据长度

在数据帧中,通常有一个 Length 字段。

  • 如果 Frame 位于报文的末尾,Length 字段可以省略,解析器直接读到报文结束。
  • 如果不是末尾,Length 字段同样使用上述的 2位标识法 可变整数编码。

QUIC生命周期

第一阶段:连接建立与握手(长报文头阶段)

在这个阶段,QUIC 使用 Long Header(长报文头),因为双方需要交换版本信息、连接 ID(CID)并验证身份。

1. Initial Packet(初始报文)

  • 发送方:客户端 服务器。
  • 内含帧:
    • CRYPTO:包含 TLS 1.3 的 ClientHello。
    • PADDING:强制填充到 1200 字节,防止放大攻击。
  • 目的:发起连接,开始密钥交换。

2. Retry Packet(重试报文 - 可选)

  • 发送方:服务器 客户端。
  • 用途:如果服务器怀疑客户端 IP 是伪造的,会发一个带有 Token 的 Retry 包。客户端必须用这个 Token 重新发一个 Initial 包,以证明自己能收到回包。

3. Initial + Handshake Packet(服务器响应)

  • 发送方:服务器 客户端。
  • 内含帧:
    • ACK:确认收到客户端的 Initial。
    • CRYPTO:包含 ServerHello。
    • Handshake 报文:包含证书(Certificate)和握手完成(Finished)信号。
  • 目的:确立加密参数,完成服务器身份验证。

4. 0-RTT Packet(预热数据 - 可选)

  • 发送方:客户端 服务器。
  • 前提:非首次连接,客户端缓存了服务器的 Token。
  • 内含帧:STREAM 帧。
  • 目的:在握手还没彻底完事时,直接发业务数据,实现零延迟。

0-RTT Packet一般会和Initial Packet合并后一起发送。

一个典型的 0-RTT 启动包(UDP 包)看起来是这样的:

+-----------------------------------------------------------------------+
|  UDP Header (Dest Port: 443, etc.)                                    |
+-----------------------------------------------------------------------+
|  QUIC Initial Packet                                                  |
|  - Frame: CRYPTO (ClientHello + Session Ticket)                       |
|  - Frame: PADDING (为了安全凑长度)                                     |
+-----------------------------------------------------------------------+
|  QUIC 0-RTT Packet (紧跟在 Initial 后面)                               |
|  - Frame: STREAM (HTTP GET /index.html)                               |
+-----------------------------------------------------------------------+

第二阶段:数据传输(短报文头阶段)

一旦握手完成(双方收到了 Finished 信号),连接进入稳定期。此时为了降低开销,全部切换为 Short Header(短报文头)。

5. 1-RTT Packet(正常数据报文)

  • 发送方:双方互发。
  • 特点:报文头极其精简,去掉了 SCID 和版本号。
  • 内含帧:
    • STREAM:真正的网页请求、图片数据等。
    • ACK:对收到的数据进行确认。
    • MAX_DATA / MAX_STREAM_DATA:告诉对方你还能发多少数据(流量控制)。
    • PING:如果没数据发了,定期发个包保活。

第三阶段:连接迁移(保持连接阶段)

这是 QUIC 的“绝活”。当用户网络变化(如 Wi-Fi 变 5G)时,报文会发生如下演变:

6. 1-RTT Packet (New Path)

  • 现象:客户端从新的 IP/端口发出了一个 1-RTT 报文,但 Connection ID 依然是旧的。
  • 服务器动作:识别出 CID,知道是老用户换了地址,但需要验证。

7. Path Challenge / Response Packet

  • 发送方:服务器 客户端(Challenge),客户端 服务器(Response)。
  • 内含帧:PATH_CHALLENGE(8字节随机数)和 PATH_RESPONSE。
  • 目的:服务器确认这个新 IP 确实属于这个客户端,而不是黑客伪造的。验证通过后,数据继续传输。

8. NEW_CONNECTION_ID Packet

  • 发送方:双方互发。
  • 用途:为了防止网络监听者通过 CID 追踪用户,QUIC 会在传输过程中不断通过这个帧分发“备用 CID”。换网络时,客户端可以换上一个新的备用 CID。

第四阶段:连接关闭(终结阶段)

连接不能永远维持,必须优雅或强制地关闭。

9. Connection Close Packet

  • 发送方:主动关闭方 被动方。
  • 内含帧:CONNECTION_CLOSE。
  • 目的:告诉对方“我要走了”,并带上错误码(比如 NO_ERROR 或 PROTOCOL_VIOLATION)。发送后,该连接的状态被销毁。

10. Stateless Reset Packet(无状态重置)

  • 场景:服务器宕机重启了,客户端发来一个属于旧连接的包。服务器完全不认识这个包。
  • 发送方:服务器 客户端。
  • 特点:它不是一个标准的加密报文,而是一个带有特殊 Token 的 UDP 包。
  • 目的:硬性终止。告诉客户端:“我不记得这个连接了,别发了,请重新开始”。

QUIC对比TCP

一、 QUIC 相比 TCP 的核心优势

1. 极致的低延迟(握手与 0-RTT)

  • TCP: 即使是 TLS 1.3,也需要 TCP 握手 + TLS 握手,至少 1 个 RTT。旧版本甚至需要 2-3 个 RTT。
  • QUIC: 将传输和加密握手合并。首次连接 1-RTT,后续连接 0-RTT。在跨境访问或高延迟网络下,QUIC 的首字节时间(TTFB)远快于 TCP。

2. 彻底解决队头阻塞 (Head-of-Line Blocking)

  • TCP: 就像一队士兵排队过窄桥,一个人摔倒了,后面所有人都要停下来等。这是 TCP 的单流有序特性决定的。
  • QUIC: 像多条并行的车道。一个数据包丢了,只会导致那一条“流”停顿,其他流(比如网页里的不同图片)可以照常传输。

3. 连接迁移 (Connection Migration)

  • TCP: 手机 Wi-Fi 切 5G,连接必断,必须重新握手、重新登录、重新加载。
  • QUIC: 使用 Connection ID。网络切换时,物理地址变了,但逻辑连接不断。这是移动互联网时代的“杀手锏”。

4. 迭代速度快 (用户态实现)

  • TCP: 实现在操作系统内核中。更新一个拥塞控制算法(如 BBR)需要升级 Linux 内核,周期以“年”计。
  • QUIC: 实现在用户态(应用程序里)。像 Chrome 或抖音,更新一下 App 就能升级 QUIC 算法,迭代周期以“周”计。

二、 QUIC 的缺点(为什么 TCP 依然不可或缺)

1. CPU 开销更高

  • 原因: TCP 经过了几十年的优化,很多网卡硬件直接支持 “TCP 卸载”(TOE),由硬件处理分包和计算。
  • QUIC: 基于 UDP,且几乎所有数据都经过强力加密。这导致处理相同数据量时,QUIC 消耗的 CPU 资源通常比 TCP 高出 10%~20%。对于大型数据中心来说,这意味着更高的电费和服务器成本。

2. 中间设备的不友好(UDP 屏蔽)

  • 现状: 许多公司的防火墙、商场的路由器、甚至某些运营商会因为安全策略(防 DDoS)直接丢弃或限制 UDP 443 端口的流量。
  • 后果: 如果 QUIC 走不通,协议必须有回退机制(Fallback),自动切回 TCP。

3. 协议复杂度极高

  • TCP 是简单的“流”,实现起来容易。
  • QUIC 包含了传输、加密、多路复用、流量控制等一系列逻辑,实现一个稳定、高性能的 QUIC 协议栈难度极大。目前市面上成熟的实现(如 quic-go, quiche, MsQuic)大多掌握在大厂手中。

4. 对小流量并不经济

  • 如果你只是发送一个极小的传感器数据(IoT),TCP 或原生 UDP 的开销更低。QUIC 复杂的握手和加密头反而显得多余。

三、 深度对比表

特性TCP (HTTP/2)QUIC (HTTP/3)评价
基础协议TCP (内核态)UDP (用户态)QUIC 迭代快,TCP 性能稳
握手延迟1~3 RTT0~1 RTTQUIC 胜 (快)
队头阻塞存在 (影响整条连接)不存在 (流级别隔离)QUIC 胜 (弱网表现好)
连接迁移不支持 (断线)支持 (无缝)QUIC 胜 (移动端福音)
CPU 占用较低 (硬件优化成熟)较高 (软件加密开销)TCP 胜 (省资源)
网络兼容性极佳 (全世界通畅)一般 (部分防火墙拦截)TCP 胜 (兼容性)
安全性TLS 可选 (通常有)强制集成 TLS 1.3QUIC 胜 (默认安全)

四、 总结:QUIC 会完全替代 TCP 吗?

结论是:不会。

  1. 分层共存:
    • QUIC 将主霸占 “人机交互” 场景:网页浏览、短视频(TikTok/抖音)、直播、实时游戏。这些场景对延迟和网络切换极其敏感。
    • TCP 将继续霸占 “机器对机器” 场景:数据库连接、后端微服务调用、大数据传输、遗留的工业控制系统。这些场景更看重吞吐量的稳定和低 CPU 消耗。
  2. 基础设施限制: 只要还有旧设备、旧防火墙存在,TCP 就是互联网的“保底协议”。
  3. 未来的趋势: 我们正在进入一个 “双协议并行” 的时代。现代浏览器(Chrome/Safari)和 App 都会优先尝试 QUIC,如果走不通,无缝切换到 TCP。