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 5Offset 还原出图片。

为什么要发明 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 byte0x020x03(取决于是否有 ECN 网络拥塞标记)。
Largest Acked可变长整数接收方目前收到的最大 Packet Number。
Ack Delay可变长整数接收方收到包到发送 ACK 之间故意等待的时间(用于更精准计算 RTT)。
Ack Range Count可变长整数表示后面有多少个非连续的确认范围。
First Ack Range可变长整数表示从 Largest Acked 往下数,连续确认了多少个包。
Gap & Range可变长整数(重复字段) 用于描述中间“丢包”造成的空洞。
  • 设计精妙处:通过 GapRange 的组合,一个 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 LenSCID 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_ERRORPROTOCOL_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。