概述
QUIC(Quick UDP Internet Connections)是一种基于UDP的传输层协议,由Google于2012年提出,旨在解决TCP和TLS的性能瓶颈,提供更快的连接建立、更低的延迟和更强的可靠性2018年,QUIC被标准化为IETF QUIC(RFC 9000),并成为HTTP/3的底层协议
设计目标
- 减少延迟:消除
TCP的三次握手和TLS的额外往返时间(RTT) - 避免队头阻塞(
Head-of-Line Blocking):通过多路复用独立的数据流 - 连接迁移:在网络切换(如
Wi-Fi到4G)时保持连接 - 改进拥塞控制:灵活支持多种算法(如
BBR、CUBIC) - 默认加密:所有数据均加密传输,整合
TLS 1.3
QUIC 的核心特性
基于 UDP
- 绕过操作系统和中间设备对
TCP的优化限制,直接在UDP上实现可靠传输 - 避免
TCP的队头阻塞问题(TCP将数据视为单一有序流)
多路复用(Multiplexing)
- 在单个连接上并行传输多个独立的流(
Stream),每个流的数据包丢失不会阻塞其他流 - 例如:网页加载时,图片、
CSS、JavaScript可以并行传输
0-RTT 和 1-RTT 连接建立
1-RTT连接:- 首次连接时,客户端和服务端通过一次往返完成密钥协商(
TLS 1.3)
- 首次连接时,客户端和服务端通过一次往返完成密钥协商(
0-RTT连接:- 后续连接时,客户端可直接发送加密数据,无需握手(类似
TCP Fast Open)
- 后续连接时,客户端可直接发送加密数据,无需握手(类似
连接迁移
- 使用连接
ID(Connection ID)标识连接,而非传统的IP+ 端口。 - 即使设备切换网络,连接仍可保持
前向纠错(FEC)
- 发送冗余数据包(如
XOR编码),在部分丢包时无需重传即可恢复数据(可选功能)
灵活的拥塞控制
- 默认使用
CUBIC或BBR算法,并允许动态调整策略
QUIC 协议结构
概述
QUIC数据包分为两个层次:QUIC数据包(Packet):包含头部和负载QUIC帧(Frame):负载中的最小数据单元,承载实际信息
数据包头部
- 长头部:用于初始握手,包含版本、连接
ID等信息 - 短头部:用于已建立的连接,仅包含连接
ID和包号
|
1 2 3 4 5 6 7 8 9 10 11 12 13 |
+-+-+-+-+-+-+-+-+ |1| 版本 (32) | +-+-+-+-+-+-+-+-+ | 目标连接ID | +-+-+-+-+-+-+-+-+ | 源连接ID | +-+-+-+-+-+-+-+-+ | 令牌(Token) | +-+-+-+-+-+-+-+-+ | 包号(可变长度)| +-+-+-+-+-+-+-+-+ | 负载(Payload)| +-+-+-+-+-+-+-+-+ |
帧类型
STREAM:传输流数据
|
1 2 3 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | 类型 (0x08) | 流ID (变长) | 偏移量 (变长) | 长度 (变长) | 数据... | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
ACK:确认接收到的包
|
1 2 3 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | 类型 (0x02) | 最大确认包号 | 确认延迟 | 包范围计数 | 包范围... | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
CRYPTO:传输TLS握手数据CONNECTION_CLOSE:关闭连接
流
- 单向或双向,支持优先级设置
- 每个流独立处理,保证数据有序性和可靠性
QUIC协议核心机制拆解
QUIC协议连接过程
首次连接
Client Hello:客户端生成临时密钥(Ephemeral Key),发送Client Hello(包含支持的TLS版本、密钥参数等)Server Hello:服务端生成密钥,返回Server Hello、证书和加密的Finished消息- 密钥计算:双方通过
HKDF算法生成会话密钥,后续通信加密 QUIC细节:所有握手消息通过CRYPTO帧传输,而非传统的TLS Record层
0-RTT连接
Session Resumption:客户端使用之前缓存的会话密钥(PSK)直接发送加密数据- 防重放攻击:服务端通过限制
0-RTT数据的有效期和一次性令牌(Token)防御重放
关键问题
- 如何保证
0-RTT安全性?- 服务端需验证客户端
Token的有效性,且0-RTT数据不应用于敏感操作(如支付)
- 服务端需验证客户端
流(Stream)与多路复用
流类型
- 单向流(
Unidirectional):客户端到服务端或反之,用于推送数据 - 双向流(
Bidirectional):两端可同时读写,用于请求-响应模式
流标识符
- 编码为
62位整数,支持超过4 亿个并发流 - 奇偶性规则:客户端发起的流
ID为偶数,服务端为奇数,避免冲突
流控制
- 流量窗口(
Flow Control):每个流独立控制接收窗口(类似HTTP/2) - 动态调整:通过
MAX_STREAM_DATA帧通知对端窗口大小
队头阻塞的彻底解决
- 流间独立:每个流的数据包独立传输和重传
- 示例:流
1的数据包丢失不会阻塞流2的数据处理
可靠传输与丢包恢复
包编号(Packet Number)
- 每个
QUIC包有独立的递增编号,不因网络路径变化重置 - 加密保护:包号在加密后被隐藏,防止中间设备篡改
确认机制(ACK Frames)
- 显式确认:接收方通过
ACK帧告知已接收的包范围 - 延迟确认:允许接收方批量确认多个包,减少开销
快速重传(Fast Retransmit)
- 基于包号的空洞检测:若发现包号不连续,立即触发重传
- 示例:若包
3、4、5中丢失了包4,接收方会在收到包5时触发重传请求
连接迁移与 NAT 穿透
连接 ID(Connection ID)
- 由服务端分配,用于唯一标识连接(替代传统
TCP的4元组) - 动态更新:支持在连接过程中切换
Connection ID以增强隐私
NET穿透
Keep-Alive机制:定期发送探测包维持NAT映射表- 端口跳跃(
Port Hopping):通过Connection ID保持连接,即使客户端IP或端口变化
QUIC 安全性
- 默认加密:所有头部和负载均加密(除少量公共字段)
TLS 1.3整合:密钥协商与传输层协议深度集成,减少握手步骤- 防重放攻击:
0-RTT数据通过限制重放窗口和单次使用令牌(Token)增强安全性
QUIC应用场景
HTTP/3:QUIC是HTTP/3的传输层协议,提升网页加载速度- 实时通信:视频会议、在线游戏等低延迟场景
- 移动网络:应对频繁的网络切换和高丢包率
CDN优化:通过多路复用和快速重传提升内容分发效率
QUIC相关库与调试
quiche
Rust实现,支持HTTP/3
lsquic
C语言实现,轻量高效
Neqo
Rust实现,用于Firefox
Google QUIC
C++实现,Chrome浏览器底层- 关键目录
|
1 2 |
net/quic/ # QUIC 核心逻辑 net/third_party/quiche/src/quiche/quic/ # Google 原始 QUIC 实现 |
- 核心类
QuicSession:管理连接生命周期、流控制和多路复用QuicStream:单个流的实现,处理数据的收发和有序性QuicPacketCreator:构建 QUIC 数据包,处理包编号和帧封装
调试
Wireshark- 需安装
QUIC插件,过滤udp.port == 443
- 需安装
qlog:QUIC专用日志格式,记录连接事件和状态变化
|
1 2 |
# 过滤 QUIC Initial Packet udp.port == 443 && quic.long.packet_type == 0x00 |
QUIC 的底层问题与优化
QUIC 的性能挑战
UDP缓冲区限制:操作系统默认UDP接收缓冲区较小,需手动调优
|
1 2 3 |
# 调整 Linux UDP 缓冲区 sysctl -w net.core.rmem_max=2500000 sysctl -w net.core.wmem_max=2500000 |
CPU密集型加密:通过硬件加速(如AES-NI)优化TLS 1.3计算
对抗网络干扰
PMTUD(路径MTU发现):QUIC支持动态MTU探测,避免分片FEC(前向纠错):通过XOR冗余包在丢包时快速恢复数据(需权衡带宽开销)
相关文档
RFC9000RFC9114
声明:本文为原创文章,版权归Aet所有,欢迎分享本文,转载请保留出处!
你可能也喜欢
- ♥ Linux 高性能服务器编程:TCP二11/24
- ♥ Objective-C学习记述二10/01
- ♥ HTTP协议相关学习一03/22
- ♥ KWP2000协议04/14
- ♥ 网络相关11/21
- ♥ RFB 协议05/25
热评文章
- RFB 协议 0
- KWP2000协议 0
- CAN-BUS协议 0
- 51CTO:Linux C++网络编程三 0
- 网络相关 0
- HTTP协议相关学习一 0