深入 quicly:H2O 内置的 IETF QUIC 协议实现——构建、测试与 CLI 实战指南
2026/9/23 17:56:30 网站建设 项目流程
  • 后端
  • 网络

【免费下载链接】h2o

H2O - the optimized HTTP/1, HTTP/2, HTTP/3 server

项目地址:https://gitcode.com/gh_mirrors/h2/h2o
点击查看免费下载

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_DRAFT29QUICLY_PROTOCOL_VERSION_DRAFT27三个版本常量;而 deps/quicly/lib/defaults.c 中默认上下文的initial_versionQUICLY_PROTOCOL_VERSION_1,即以正式版 QUIC v1 作为默认协商版本,同时保留对早期草案版本的兼容解析。

构建 quicly

前置条件

构建 quicly 需要:

  1. 拉取子模块:quicly 通过 git submodule 管理 picotls、klib 等依赖,首次获取源码后必须执行:
    git submodule update --init --recursive
  2. OpenSSL 1.0.2 或以上版本:README 明确给出这一版本下限。deps/quicly/CMakeLists.txt 在构建期即通过FIND_PACKAGE(OpenSSL REQUIRED)强制要求 OpenSSL,并对OPENSSL_VERSION < 1.0.2的情况直接报错中止。

标准构建步骤

cmake . make

CMake 脚本中还包含几个值得注意的默认行为:

  • 默认 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):

目标说明
libquiclyquicly 核心静态库(lib/frame.clib/quicly.clib/cc-cubic.clib/loss.c等 14 个源文件)
cli可同时充当 QUIC 客户端与服务端的命令行工具(见下文)
test.t单元测试可执行文件,覆盖t/下的各模块测试
simulator基于t/simulator.c的丢包/拥塞仿真程序
examples-echo基于examples/echo.c的最小回显示例
udpfwt/udpfw.c实现的 UDP 转发工具,用于测试模拟丢包、延迟

运行测试

安装 Perl 测试依赖

quicly 的测试体系依赖 Perl 生态(Test::MoreNet::EmptyPortJSON等,依赖清单见 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 check

check是 CMake 自定义目标(deps/quicly/CMakeLists.txt):它通过prove依次执行构建目录与t/目录下的所有*.tPerl 测试脚本,并确保cliudpfwtest.t已先构建完成。测试覆盖两大类:

  • 单元测试t/simple.ct/cc.ct/frame.ct/loss.ct/ranges.ct/rate.ct/local_cid.ct/remote_cid.ct/sentmap.ct/maxsender.ct/pacer.ct/jumpstart.ct/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 --help

usage()函数(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(-Nenforce_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(默认)、cubiccubic-legacypicocuback;可附加初始拥塞窗口(包数,默认 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_local1 MB
max_stream_data.bidi_remote11 MB
max_stream_data.uni1 MB
max_streams_bidi100
max_streams_uni0
max_idle_timeout30,000 ms
max_udp_payload_size1472 字节
initial_egress_max_udp_payload_size1280 字节
initcwnd_packets10 包
max_crypto_bytes65,536 字节
pre_validation_amplification_limit3(放大攻击防护倍数)
handshake_timeout_rtt_multiplier400
initial_versionQUIC 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_tquicly_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_acceptvalidate_token等函数(src/main.c)。

协议层之上的 HTTP/3 语义(帧、QPACK、服务端逻辑)位于 lib/http3(frame.cqpack.ccommon.cserver.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

项目地址:https://gitcode.com/gh_mirrors/h2/h2o
点击查看免费下载
上一篇:Granite-4.1-8B工具调用终极教程:3步实现天气查询/API集成等实用功能
下一篇:async-http-client与Quarkus原生应用:终极性能优化指南

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询