cloudflare/quiche
GitHub: cloudflare/quiche
Cloudflare 开源的 QUIC 传输协议和 HTTP/3 实现库,提供底层 API 用于构建高性能网络应用
Stars: 11296 | Forks: 945

[](https://crates.io/crates/quiche)
[](https://docs.rs/quiche)
[](https://opensource.org/licenses/BSD-2-Clause)

[quiche] 是 [IETF] 指定的 QUIC 传输协议和 HTTP/3 的实现。它提供了用于处理 QUIC 数据包和处理连接状态的底层 API。应用程序负责提供 I/O(例如套接字处理)以及支持定时器的事件循环。
关于 quiche 的诞生及其设计见解的更多信息,您可以阅读 Cloudflare 博客上的[文章],其中有更详细的介绍。
## 谁在使用 quiche?
### Cloudflare
quiche 支持了 Cloudflare 边缘网络的 [HTTP/3 支持][cloudflare-http3]。[cloudflare-quic.com](https://cloudflare-quic.com) 网站可用于测试和实验。
### Android
Android 的 DNS 解析器使用 quiche [实现 DNS over HTTP/3][android-http3]。
### curl
quiche 可以[集成到 curl][curl-http3] 中以提供 HTTP/3 支持。
## 入门指南
### 命令行应用程序
在深入了解 quiche API 之前,这里有几个关于如何使用 [quiche-apps](apps/) crate 中提供的 quiche 工具的示例。这些不适用于生产环境;请参阅[免责声明和说明](#disclaimers-and-notes)。
按照 [building](#building) 部分中提到的命令克隆项目后,可以按如下方式运行客户端:
```
$ cargo run --bin quiche-client -- https://cloudflare-quic.com/
```
而服务器可以按如下方式运行:
```
$ cargo run --bin quiche-server -- --cert apps/src/bin/cert.crt --key apps/src/bin/cert.key
```
(请注意,提供的证书是自签名的,不应在生产环境中使用)
使用 `--help` 命令行标志可以获取每个工具选项的更详细说明。
### 配置连接
使用 quiche 建立 QUIC 连接的第一步是创建一个 [`Config`] 对象:
```
let mut config = quiche::Config::new(quiche::PROTOCOL_VERSION)?;
config.set_application_protos(&[b"example-proto"]);
// Additional configuration specific to application and use case...
```
[`Config`] 对象控制 QUIC 连接的重要方面,例如 QUIC 版本、ALPN ID、流控制、拥塞控制、空闲超时以及其他属性或功能。
QUIC 是一种通用传输协议,有几个配置属性没有合理的默认值。例如,任何特定类型的并发流的允许数量取决于运行在 QUIC 之上的应用程序以及其他特定于用例的考虑因素。
quiche 将几个属性默认为零,应用程序很可能需要使用以下方法将这些属性设置为其他值以满足其需求:
- [`set_initial_max_streams_bidi()`]
- [`set_initial_max_streams_uni()`]
- [`set_initial_max_data()`]
- [`set_initial_max_stream_data_bidi_local()`]
- [`set_initial_max_stream_data_bidi_remote()`]
- [`set_initial_max_stream_data_uni()`]
[`Config`] 还包含 TLS 配置。这可以通过现有对象上的修改器进行更改,或者通过手动构建 TLS 上下文并使用 [`with_boring_ssl_ctx_builder()`] 创建配置。
一个配置对象可以在多个连接之间共享。
### 连接设置
在客户端,可以使用 [`connect()`] 实用函数创建新连接,而 [`accept()`] 用于服务器:
```
// Client connection.
let conn = quiche::connect(Some(&server_name), &scid, local, peer, &mut config)?;
// Server connection.
let conn = quiche::accept(&scid, None, local, peer, &mut config)?;
```
### 处理传入数据包
使用连接的 [`recv()`] 方法,应用程序可以处理从网络传入的属于该连接的数据包:
```
let to = socket.local_addr().unwrap();
loop {
let (read, from) = socket.recv_from(&mut buf).unwrap();
let recv_info = quiche::RecvInfo { from, to };
let read = match conn.recv(&mut buf[..read], recv_info) {
Ok(v) => v,
Err(e) => {
// An error occurred, handle it.
break;
},
};
}
```
### 生成传出数据包
传出数据包使用连接的 [`send()`] 方法生成:
```
loop {
let (write, send_info) = match conn.send(&mut out) {
Ok(v) => v,
Err(quiche::Error::Done) => {
// Done writing.
break;
},
Err(e) => {
// An error occurred, handle it.
break;
},
};
socket.send_to(&out[..write], &send_info.to).unwrap();
}
```
当发送数据包时,应用程序负责维护一个定时器以响应基于时间的连接事件。定时器到期时间可以使用连接的 [`timeout()`] 方法获取。
```
let timeout = conn.timeout();
```
应用程序负责提供定时器实现,该实现可以特定于所使用的操作系统或网络框架。当定时器到期时,应调用连接的 [`on_timeout()`] 方法,之后可能需要在网络上发送额外的数据包:
```
// Timeout expired, handle it.
conn.on_timeout();
// Send more packets as needed after timeout.
loop {
let (write, send_info) = match conn.send(&mut out) {
Ok(v) => v,
Err(quiche::Error::Done) => {
// Done writing.
break;
},
Err(e) => {
// An error occurred, handle it.
break;
},
};
socket.send_to(&out[..write], &send_info.to).unwrap();
}
```
#### Pacing
建议应用程序[节奏控制 (pace)][pace] 传出数据包的发送,以避免产生可能导致短期网络拥塞和丢包的数据包突发。
quiche 通过 [`send()`] 方法返回的 [`SendInfo`] 结构的 [`at`] 字段,为传出数据包提供发送节奏提示。该字段表示特定数据包应发送到网络的时间。
应用程序可以通过平台特定的机制(例如 Linux 上的 [`SO_TXTIME`] 套接字选项)或自定义方法(例如使用用户空间定时器)人为延迟数据包的发送来使用这些提示。
### 发送和接收流数据
经过一些来回通信后,连接将完成握手,并将准备好发送或接收应用程序数据。
可以使用 [`stream_send()`] 方法在流上发送数据:
```
if conn.is_established() {
// Handshake completed, send some data on stream 0.
conn.stream_send(0, b"hello", true)?;
}
```
应用程序可以使用连接的 [`readable()`] 方法检查是否有任何可读流,该方法返回所有有未读数据的流的迭代器。
然后可以使用 [`stream_recv()`] 方法从可读流中检索应用程序数据:
```
if conn.is_established() {
// Iterate over readable streams.
for stream_id in conn.readable() {
// Stream is readable, read until there's no more data.
while let Ok((read, fin)) = conn.stream_recv(stream_id, &mut buf) {
println!("Got {} bytes on stream {}", read, stream_id);
}
}
}
```
### HTTP/3
quiche [HTTP/3 模块][HTTP/3 module] 提供了用于在 QUIC 传输协议之上发送和接收 HTTP 请求和响应的高级 API。
请查看 [quiche/examples/] 目录,获取关于如何使用 quiche API 的更完整示例,包括如何在 C/C++ 应用程序中使用 quiche 的示例(详见下文)。
## 从 C/C++ 调用 quiche
quiche 在 Rust API 之上公开了一个[精简的 C API][thin C API],可以更轻松地将 quiche 集成到 C/C++ 应用程序中(以及允许通过某种形式的 FFI 调用 C API 的其他语言)。C API 遵循与 Rust 相同的设计,除了 C 语言本身施加的限制。
运行 ``cargo build`` 时,将自动构建一个名为 ``libquiche.a`` 的静态库。它是完全独立的,可以直接链接到 C/C++ 应用程序中。
请注意,为了启用 FFI API,必须启用 ``ffi`` 功能(默认情况下禁用),方法是将 ``--features ffi`` 传递给 ``cargo``。
## 构建
构建 quiche 需要 Rust 1.85 或更高版本。可以使用 [rustup](https://rustup.rs/) 安装最新的稳定版 Rust。
设置好 Rust 构建环境后,可以使用 git 获取 quiche 源代码:
```
$ git clone --recursive https://github.com/cloudflare/quiche
```
然后使用 cargo 构建:
```
$ cargo build --examples
```
cargo 也可用于运行测试套件:
```
$ cargo test
```
请注意,[BoringSSL](用于实现基于 TLS 的 QUIC 加密握手)需要构建并链接到 quiche。当使用 cargo 构建 quiche 时,这是自动完成的,但在构建过程中需要 `cmake` 命令。在 Windows 上,您还需要 [NASM](https://www.nasm.us/)。[官方 BoringSSL 文档](https://github.com/google/boringssl/blob/master/BUILDING.md) 有更多详细信息。
或者,您可以通过使用 ``QUICHE_BSSL_PATH`` 环境变量配置 BoringSSL 目录,来使用您自己的 BoringSSL 自定义构建:
```
$ QUICHE_BSSL_PATH="/path/to/boringssl" cargo build --examples
```
或者,您可以使用 [OpenSSL/quictls]。要使 quiche 能够使用此供应商,可以将 ``openssl`` 功能添加到 ``--feature`` 列表中。请注意,如果使用此供应商,则不支持 ``0-RTT``。
### 为 Android 构建
使用 [cargo-ndk](v2.0 或更高版本)可以为 Android(NDK 版本 19 或更高版本,推荐 21)构建 quiche。
首先需要安装 [Android NDK],可以使用 Android Studio 或直接安装,并且需要将 `ANDROID_NDK_HOME` 环境变量设置为 NDK 安装路径,例如:
```
$ export ANDROID_NDK_HOME=/usr/local/share/android-ndk
```
然后可以按如下方式安装所需 Android 架构的 Rust 工具链:
```
$ rustup target add aarch64-linux-android armv7-linux-androideabi i686-linux-android x86_64-linux-android
```
请注意,所有目标架构的最低 API 级别为 21。
还需要安装 [cargo-ndk](v2.0 或更高版本):
```
$ cargo install cargo-ndk
```
最后,可以使用以下过程构建 quiche 库。请注意,`-t ` 和 `-p ` 选项是必需的。
```
$ cargo ndk -t arm64-v8a -p 21 -- build --features ffi
```
有关更多信息,请参阅 [build_android_ndk19.sh]。
### 为 iOS 构建
要为 iOS 构建 quiche,您需要以下内容:
- 安装 Xcode 命令行工具。您可以使用 Xcode 或使用以下命令安装它们:
```
$ xcode-select --install
```
- 安装 iOS 架构的 Rust 工具链:
```
$ rustup target add aarch64-apple-ios x86_64-apple-ios
```
- 安装 `cargo-lipo`:
```
$ cargo install cargo-lipo
```
要构建 libquiche,请运行以下命令:
```
$ cargo lipo --features ffi
```
或
```
$ cargo lipo --features ffi --release
```
iOS 构建在 Xcode 10.1 和 Xcode 11.2 中进行了测试。
### 构建 Docker 镜像
为了构建 Docker 镜像,只需运行以下命令:
```
$ make docker-build
```
您可以在以下 Docker Hub 仓库中找到 quiche Docker 镜像:
- [cloudflare/quiche](https://hub.docker.com/repository/docker/cloudflare/quiche)
- [cloudflare/quiche-qns](https://hub.docker.com/repository/docker/cloudflare/quiche-qns)
每当 quiche master 分支更新时,`latest` 标签都会更新。
**cloudflare/quiche**
提供安装在 /usr/local/bin 中的服务器和客户端。
**cloudflare/quiche-qns**
提供用于在 [quic-interop-runner](https://github.com/marten-seemann/quic-interop-runner) 中测试 quiche 的脚本。
## 免责声明和说明
⚠️ 此存储库包含许多客户端和服务器示例应用程序,旨在演示 quiche 库 API 的简单用法。它们不适用于生产环境;不提供任何性能、安全性或可靠性保证。
## 版权
版权所有 (C) 2018-2019, Cloudflare, Inc.
有关许可证,请参阅 [COPYING]。
标签:Cloudflare, DNS over HTTP/3, DoH3, HTTP/3, IETF, IP 地址批量处理, libquiche, MITRE ATT&CK, QUIC, Rust, socket编程, UDP, 传输层, 低延迟, 内核驱动, 加密传输, 协议栈, 可视化界面, 系统编程, 网络协议, 网络安全, 网络库, 网络流量审计, 网络通信, 边缘计算, 通知系统, 通知系统, 隐私保护