- 后端
- 网络
【免费下载链接】h2o
H2O - the optimized HTTP/1, HTTP/2, HTTP/3 server
quicly 是 H2O HTTP 服务器内部使用的 IETF QUIC 协议实现,从零编写、专为嵌入 H2O 而设计,为其 HTTP/3 能力提供传输层基石。本文以 deps/quicly/README.md 为主线,完整覆盖其构建、依赖、测试与cli命令行工具的客户端/服务端用法,并结合仓库源码补充默认传输参数、选项语义与 H2O 集成细节,帮助你从“能编译”走向“能调试、能调参、能理解”。
quicly 是什么:定位与设计目标
根据 deps/quicly/README.md 的定义,quicly 是一份IETF QUIC 协议实现(IETF QUIC protocol implementation),其最显著的特点是:
- 从零(from the ground up)编写,并非对既有实现的移植或封装;
- 首要使用场景是嵌入 H2O HTTP 服务器,为 H2O 提供 QUIC / HTTP/3 传输能力;
- 采用MIT License开源许可(许可证全文见 deps/quicly/LICENSE)。
从仓库结构看,quicly 的代码集中在 deps/quicly/lib(核心实现)与 deps/quicly/include/quicly(公共头文件),并依赖两个关键子库:
- picotls(deps/quicly/deps/picotls):负责 TLS 1.3 握手与加解密,quicly 通过
ptls_*API 完成 QUIC 所需的传输层安全; - klib(deps/quicly/deps/klib):提供哈希表、字符串、列表等基础容器。
在协议版本方面,从 deps/quicly/include/quicly.h 可以看到 quicly 定义了QUICLY_PROTOCOL_VERSION_1(QUIC v1)、QUICLY_PROTOCOL_VERSION_DRAFT29与QUICLY_PROTOCOL_VERSION_DRAFT27三个版本常量;而 deps/quicly/lib/defaults.c 中默认上下文的initial_version为QUICLY_PROTOCOL_VERSION_1,即以正式版 QUIC v1 作为默认协商版本,同时保留对早期草案版本的兼容解析。
构建 quicly
前置条件
构建 quicly 需要:
- 拉取子模块:quicly 通过 git submodule 管理 picotls、klib 等依赖,首次获取源码后必须执行:
git submodule update --init --recursive - OpenSSL 1.0.2 或以上版本:README 明确给出这一版本下限。deps/quicly/CMakeLists.txt 在构建期即通过
FIND_PACKAGE(OpenSSL REQUIRED)强制要求 OpenSSL,并对OPENSSL_VERSION < 1.0.2的情况直接报错中止。
标准构建步骤
cmake . makeCMake 脚本中还包含几个值得注意的默认行为:
- 默认 Release 构建:
CMAKE_BUILD_TYPE未指定时自动设为Release(deps/quicly/CMakeLists.txt),与 CMake 默认的 Debug 行为不同; - 使用
-std=c99 -Wall -g -DQUICLY_USE_TRACER=1编译,开启内置跟踪器支持; - Linux 下额外追加
-D_GNU_SOURCE -pthread(deps/quicly/CMakeLists.txt)。
指定非标准位置的 OpenSSL
如果 OpenSSL 安装在非标准目录,可以通过PKG_CONFIG_PATH环境变量告知 CMake 其 pkg-config 文件位置:
PKG_CONFIG_PATH=/path/to/openssl/lib/pkgconfig cmake .构建产物一览
构建完成后,make会生成多个目标(对应 deps/quicly/CMakeLists.txt):
| 目标 | 说明 |
|---|---|
libquicly | quicly 核心静态库(lib/frame.c、lib/quicly.c、lib/cc-cubic.c、lib/loss.c等 14 个源文件) |
cli | 可同时充当 QUIC 客户端与服务端的命令行工具(见下文) |
test.t | 单元测试可执行文件,覆盖t/下的各模块测试 |
simulator | 基于t/simulator.c的丢包/拥塞仿真程序 |
examples-echo | 基于examples/echo.c的最小回显示例 |
udpfw | t/udpfw.c实现的 UDP 转发工具,用于测试模拟丢包、延迟 |
运行测试
安装 Perl 测试依赖
quicly 的测试体系依赖 Perl 生态(Test::More、Net::EmptyPort、JSON等,依赖清单见 deps/quicly/cpanfile),需要先用cpanm安装:
# 使用系统 Perl 时,加 --sudo curl -sL https://cpanmin.us | perl - --sudo --self-upgrade cpanm --installdeps --notest --sudo . # 使用用户级 Perl 时,去掉 --sudo curl -sL https://cpanmin.us | perl - --self-upgrade cpanm --installdeps --notest .执行测试
make checkcheck是 CMake 自定义目标(deps/quicly/CMakeLists.txt):它通过prove依次执行构建目录与t/目录下的所有*.tPerl 测试脚本,并确保cli、udpfw、test.t已先构建完成。测试覆盖两大类:
- 单元测试:
t/simple.c、t/cc.c、t/frame.c、t/loss.c、t/ranges.c、t/rate.c、t/local_cid.c、t/remote_cid.c、t/sentmap.c、t/maxsender.c、t/pacer.c、t/jumpstart.c、t/stream-concurrency.c等,逐模块验证帧解析、拥塞控制、丢包恢复、连接迁移等内部逻辑; - 端到端测试:如 deps/quicly/t/e2e.t,会实际拉起
cli服务端,再以客户端发起请求。例如t/e2e.t中的 "hello" 用例执行$cli -e $tempdir/events -p /12 127.0.0.1 $port,期望输出hello world,并进一步检查事件日志能否被 misc/qlog-adapter.py 转换为标准 qlog 格式——这也是用端到端测试验证协议实现正确性的典型做法。
使用 cli 运行 quicly
cli(源码位于 deps/quicly/src/cli.c)是一个既可作为客户端、也可作为服务端的命令行程序。其行为由是否提供证书与私钥决定:
客户端模式
只需给出对端主机名与端口号:
./cli host port例如连接本地 4433 端口并请求/12路径:
./cli -p /12 127.0.0.1 4433服务端模式
需要提供证书、私钥文件,以及要绑定的监听地址与端口:
./cli -c server.crt -k server.key 0.0.0.0 4433-c:证书文件(PEM 格式);-k:私钥文件;- 绑定地址
0.0.0.0表示监听所有 IPv4 接口,端口 4433 为 QUIC/UDP 端口。
仓库中可直接用于测试的证书/密钥对位于 deps/quicly/t/assets/server.crt 与 deps/quicly/t/assets/server.key,也有 ECDSA 密钥对 deps/quicly/t/assets/ec256-key-pair.pem;此外 deps/quicly/misc/quic-interop-runner 目录也提供了用于互操作测试的server.crt/server.key。
查看全部选项
./cli --helpusage()函数(deps/quicly/src/cli.c)会打印完整帮助,包括下文列出的全部参数。
cli 命令行选项全览
根据./cli --help的输出(即src/cli.c中的usage()),可将选项按用途分类如下:
连接与运行模式
| 选项 | 说明 |
|---|---|
host port | 位置参数;客户端模式为对端地址,服务端模式为监听地址与 UDP 端口 |
-c <cert-file> | 服务端证书文件;缺省时以客户端身份运行 |
-k <key-file> | 服务端私钥文件(与-c搭配) |
-a <alpn> | ALPN 标识符,可重复指定多个候选(如h3) |
-p <path> | 客户端请求的路径,可多次指定 |
-P <path> | 客户端请求的路径,并将响应保存到文件,可多次指定 |
-O | 抑制输出(压测时使用) |
安全与握手
| 选项 | 说明 |
|---|---|
-V | 使用系统默认 CA 证书校验对端 |
-W <public-key-file> | 使用 RFC 7250 裸公钥;客户端模式下指定期望的服务端公钥 |
-s <session-file> | 会话票据(session ticket)的加载/存储文件,用于 0-RTT 与会话恢复 |
-N | 客户端强制启用 HelloRetryRequest(-N即enforce_retry) |
-n | 客户端强制启用版本协商 |
-E | 展开 Client Hello(发送多个 Initial 包以放大握手) |
--ech-config <file> | ECH(Encrypted Client Hello)配置列表文件;置空文件可发送 ECH grease |
--ech-key <file> | 与--ech-config对应的 ECH 私钥 |
-x <named-group> | 椭圆曲线命名组,默认secp256r1 |
-y <cipher-suite> | TLS 密码套件,默认使用全部 |
传输与流控制
| 选项 | 说明 |
|---|---|
-b <bytes> | 发送/接收 UDP socket 缓冲区大小(字节) |
-u <size> | 初始 UDP 数据报负载大小 |
-U <size> | 最大 UDP 数据报负载大小 |
-M <bytes> | 单流最大数据量(max stream data),默认 1 MB |
-m <bytes> | 连接级最大数据量(max data),默认 16 MB |
-X | 最大双向流数量,默认 100 |
-I <ms> | 空闲超时,默认 600,000 ms(10 分钟) |
--max-crypto-bytes <N> | CRYPTO 流最大长度限制 |
-B <cid-key> | 服务端 CID 加密密钥(缺省随机生成) |
-R | 服务端强制要求 Retry 数据包 |
--sockfd <fd> | 使用指定的已创建 UDP socket 文件描述符 |
-G | 启用 UDP 通用分段卸载(GSO) |
拥塞控制与丢包恢复
| 选项 | 说明 |
|---|---|
-C <algo>[:<iw>[:<p>]] | 拥塞控制算法:reno(默认)、cubic、cubic-legacy、pico、cuback;可附加初始拥塞窗口(包数,默认 10)与是否启用 pacing |
--jumpstart-default <wnd> | 新连接 jumpstart 拥塞窗口(包数) |
--jumpstart-max <wnd> | 会话恢复连接的最大 jumpstart 拥塞窗口 |
--rapid-start | 开启 rapid start |
--disable-ecn | 关闭 ECN 支持(默认开启) |
--disregard-app-limited | 应用受限时也增大 CWND |
-f <fraction> | 将 ACK 频率提高到 CWND 的指定比例(默认 0) |
-r <ms> | 初始 PTO(探测超时) |
-S <n> | 推测性 PTO 次数 |
-K <n> | 每发送 n 个包执行一次密钥更新 |
--no-normalize-cc-mtu | 禁用拥塞窗口增长的包大小归一化 |
调试与诊断
| 选项 | 说明 |
|---|---|
-v/-vv | 详细输出;-vv额外输出逐包 hexdump |
-e <file> | 事件日志文件(可被 qlog-adapter 转换) |
-l <file> | 记录流量密钥(traffic secrets) |
--exit-after-handshake | 握手结束后立即退出,不发送应用数据 |
--calc-initial-secret <dcid> | 给定 DCID 计算 Initial 阶段的客户端/服务端流量密钥 |
--decrypt-packet <secret>[:<dcid-len>] | 给定流量密钥解密 QUIC 包并打印明文 |
--encrypt-packet <secret> | 对未加密包按给定密钥加密输出 |
-h | 打印帮助 |
默认参数与调优:源码中的两个内置 profile
cli 的默认传输参数并非硬编码在cli.c,而是来自 deps/quicly/lib/defaults.c 中的两个全局上下文:
quicly_spec_context:采用 IETF 规范建议值(deps/quicly/lib/defaults.c);quicly_performant_context:面向 HTTP 场景的延迟优化 profile,主要差异在于使用QUICLY_LOSS_PERFORMANT_CONF的丢包恢复配置。
cli 在main()中以ctx = quicly_spec_context;作为起点(deps/quicly/src/cli.c)。两个 profile 的传输参数一致,关键默认值如下(对应-m、-M、-X、-I等选项的覆盖目标):
| 参数 | 默认值 |
|---|---|
max_data(连接级流控) | 16 MB |
max_stream_data.bidi_local | 1 MB |
max_stream_data.bidi_remote | 11 MB |
max_stream_data.uni | 1 MB |
max_streams_bidi | 100 |
max_streams_uni | 0 |
max_idle_timeout | 30,000 ms |
max_udp_payload_size | 1472 字节 |
initial_egress_max_udp_payload_size | 1280 字节 |
initcwnd_packets | 10 包 |
max_crypto_bytes | 65,536 字节 |
pre_validation_amplification_limit | 3(放大攻击防护倍数) |
handshake_timeout_rtt_multiplier | 400 |
initial_version | QUIC v1 |
enable_ratio.jumpstart | 开(255) |
enable_ratio.rapid_start | 关(0) |
enable_ratio.ecn | 开(255) |
enable_ratio.pacing | 关(0) |
理解这些默认值有助于解读./cli --help中“default”标注的来源,例如-m的 16 MB、-M的 1 MB、-X的 100 流,都与quicly_spec_context一一对应。实际接入 H2O 时,这些参数同样以quicly_spec_context为蓝本:在 src/main.c 中,H2O 为每个 HTTP/3 listener 分配quicly_context_t时即执行*quic = quicly_spec_context;再按配置覆盖。
在 H2O 中的角色:HTTP/3 的传输引擎
quicly 之于 H2O 的核心价值体现在 HTTP/3 支持上。从 src/main.c 的集成代码可以看到完整的调用关系:
- H2O 直接包含
quicly.h,并持有quicly_context_t、quicly_conn_t等对象(src/main.c); - 建立监听时通过
quicly_amend_ptls_context()完善 TLS 上下文(src/main.c),并设置h2o_http3_alpn进行 ALPN 协商(src/main.c); - 服务端在收到 SNI 后可按证书配置动态切换拥塞控制算法
quicly_set_cc()(src/main.c); - HTTP/3 的 QPACK 动态表默认取 16 KB 编码/解码表(src/main.c);
- 基于 UDP 的收包、Retry 校验、地址令牌验证与 QUIC 连接接受逻辑集中在
on_http3_accept、validate_token等函数(src/main.c)。
协议层之上的 HTTP/3 语义(帧、QPACK、服务端逻辑)位于 lib/http3(frame.c、qpack.c、common.c、server.c),quicly 则负责其下的传输与安全层。因此可以说:H2O 的 HTTP/3 = quicly(QUIC 传输)+ picotls(TLS 1.3)+ lib/http3(HTTP 语义)。
小结
quicly 是一个 MIT 许可、为 H2O 量身打造的 IETF QUIC 实现。通过git submodule update --init --recursive && cmake . && make即可完成构建,make check跑通单元与端到端测试,随后用cli一行命令就能搭起 QUIC 服务端或客户端。深入源码后还能看到:cli的每个调优开关背后都对应 deps/quicly/lib/defaults.c 中的具体参数,而 H2O 正是基于quicly_spec_context这个默认 profile,叠加 src/main.c 中的集成逻辑,将 quicly 变成本项目 HTTP/3 能力的传输基石。若要继续深入,建议从 deps/quicly/include/quicly.h 的公开 API 与 deps/quicly/t 的测试用例入手,前者定义协议常量与回调类型,后者展示了每个模块的预期行为。
- 后端
- 网络
【免费下载链接】h2o
H2O - the optimized HTTP/1, HTTP/2, HTTP/3 server
相关推荐
ngtcp2:实现IETF QUIC协议的深度探索
ngtcp2:实现IETF QUIC协议的深度探索 项目介绍 ngtcp2 是一个致力于实现互联网工程任务组(IETF)定义的QUIC协议的开源项目。QUIC协
网络通信CANN/ops-nn Swish激活函数算子
aclnnSwish 📄 查看源码 https://link.gitcode.com/i/4103db1e75f48bf2ca780e9bf98d9fae 产
人工智能算子库深度学习CANNAscendquiche 实践指南:用 Rust 构建 IETF QUIC 与 HTTP/3 应用
quiche 实践指南:用 Rust 构建 IETF QUIC 与 HTTP/3 应用 本篇技术指南以 Cloudflare 出品的 quiche 开源仓库主文
网络通信后端
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考