본문으로 건너뛰기

© 2026 Molayo

GH Trending릴리즈2026. 05. 16. 21:16

cloudflare/quiche

요약

quiche는 IETF 표준 QUIC 전송 프로토콜 및 HTTP/3의 저수준(low-level) 구현체입니다. 이 라이브러리는 QUIC 패킷 처리와 연결 상태 관리를 위한 API를 제공하며, 애플리케이션은 이벤트 루프와 타이머 처리에 대한 책임을 가집니다. quiche는 Cloudflare 엣지 네트워크의 HTTP/3 지원에 사용되며, Android DNS 리졸버에서도 활용됩니다. 개발자는 `Config` 객체를 통해 QUIC 버전, 흐름 제어, 혼잡 제어 등 다양한 연결 속성을 설정하고, `connect()` 또는 `accept()`를 사용하여 연결을 수립하며, `recv()`와 `send()` 메서드를 이용해 패킷을 처리합니다.

핵심 포인트

  • quiche는 IETF 표준 QUIC 및 HTTP/3의 저수준 구현체이다.
  • 애플리케이션은 이벤트 루프와 타이머 관리를 직접 책임져야 한다.
  • 연결 설정 시 `Config` 객체를 사용하여 다양한 속성(버전, 흐름 제어 등)을 세밀하게 조정할 수 있다.
  • 클라이언트 연결은 `connect()`로, 서버 연결은 `accept()`를 통해 생성한다.
  • 패킷 처리는 `recv()`와 `send()` 메서드를 사용하며, 시간 기반 이벤트는 타이머(`timeout()`)를 통해 관리된다.

quiche는 IETF에서 규정한 QUIC 전송 프로토콜 (transport protocol) 및 HTTP/3의 구현체입니다. 이는 QUIC 패킷을 처리하고 연결 상태 (connection state)를 관리하기 위한 저수준 API (low level API)를 제공합니다. 애플리케이션은 I/O (예: 소켓 처리)뿐만 아니라 타이머 (timers)를 지원하는 이벤트 루프 (event loop)를 제공할 책임이 있습니다.

quiche가 어떻게 탄생했는지와 설계에 대한 통찰력을 얻기 위한 더 자세한 정보는 Cloudflare의 블로그 포스트에서 확인할 수 있습니다.

quiche는 Cloudflare 엣지 네트워크 (edge network)의 HTTP/3 지원을 구동합니다. cloudflare-quic.com 웹사이트는 테스트 및 실험용으로 사용할 수 있습니다.

Android의 DNS 리졸버 (DNS resolver)는 DNS over HTTP/3를 구현하기 위해 quiche를 사용합니다.

quiche는 curl에 통합되어 HTTP/3 지원을 제공할 수 있습니다.

quiche API를 살펴보기 전에, quiche-apps 크레이트 (crate)의 일부로 제공되는 quiche 도구들을 사용하는 몇 가지 예시가 있습니다. 이것들은 운영 환경 (production environments)에는 적합하지 않으므로, 면책 조항 및 주의 사항을 참조하십시오.

빌드 섹션에 언급된 명령에 따라 프로젝트를 클론 (cloning)한 후, 클라이언트 (client)는 다음과 같이 실행할 수 있습니다:

$ cargo run --bin quiche-client -- https://cloudflare-quic.com/

반면 서버 (server)는 다음과 같이 실행할 수 있습니다:

$ cargo run --bin quiche-server -- --cert apps/src/bin/cert.crt --key apps/src/bin/cert.key

(제공된 인증서는 자체 서명된 것이며 운영 환경에서 사용해서는 안 된다는 점에 유의하십시오)

각 도구 옵션에 대한 더 자세한 설명을 얻으려면 --help 명령줄 플래그 (command-line flag)를 사용하십시오.

quiche를 사용하여 QUIC 연결을 설정하는 첫 번째 단계는 Config 객체를 생성하는 것입니다:

let mut config = quiche::Config::new(quiche::PROTOCOL_VERSION)?;
config.set_application_protos(&[b"example-proto"]);
// 애플리케이션 및 사용 사례에 특화된 추가 구성...

Config 객체는 QUIC 버전, ALPN ID, 흐름 제어 (flow control), 혼잡 제어 (congestion control), 유휴 시간 제한 (idle timeout) 및 기타 속성 또는 기능과 같은 QUIC 연결의 중요한 측면을 제어합니다.

QUIC은 범용 전송 프로토콜 (transport protocol)이며, 합리적인 기본값이 없는 여러 설정 속성들이 존재합니다. 예를 들어, 특정 유형의 허용된 동시 스트림 (concurrent streams) 수는 QUIC 위에서 실행되는 애플리케이션이나 기타 사용 사례별 고려 사항에 따라 달라집니다.

quiche는 여러 속성을 0으로 기본 설정하며, 애플리케이션은 다음 메서드들을 사용하여 요구 사항을 충족하기 위해 이를 다른 값으로 설정해야 할 가능성이 높습니다:

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 설정을 보유합니다. 이는 기존 객체에 대한 뮤테이터 (mutators)를 통해 변경하거나, TLS 컨텍스트 (TLS context)를 수동으로 구성하고 with_boring_ssl_ctx_builder()를 사용하여 설정을 생성함으로써 변경할 수 있습니다.

설정 객체 (configuration object)는 여러 연결 (connections) 간에 공유될 수 있습니다.

클라이언트 측에서는 connect() 유틸리티 함수를 사용하여 새로운 연결을 생성할 수 있으며, 서버의 경우 accept()를 사용합니다:

// 클라이언트 연결.
let conn = quiche::connect(Some(&server_name), &scid, local, peer, &mut config)?;
// 서버 연결.
...

연결의 recv() 메서드를 사용하여 애플리케이션은 네트워크로부터 해당 연결에 속하는 들어오는 패킷 (incoming packets)을 처리할 수 있습니다:

let to = socket.local_addr().unwrap();
loop {
let (read, from) = socket.recv_from(&mut buf).unwrap();
...

대신, 나가는 패킷 (outgoing packets)은 연결의 send() 메서드를 사용하여 생성됩니다:

loop {
let (write, send_info) = match conn.send(&mut out) {
Ok(v) => v,
...

패킷이 전송될 때, 애플리케이션은 시간 기반 연결 이벤트에 반응하기 위해 타이머 (timer)를 유지할 책임이 있습니다. 타이머 만료는 연결의 timeout() 메서드를 사용하여 얻을 수 있습니다.

let timeout = conn.timeout();

애플리케이션은 사용 중인 운영 체제(Operating System)나 네트워킹 프레임워크에 특화될 수 있는 타이머 구현을 제공할 책임이 있습니다. 타이머가 만료되면 연결의 on_timeout() 메서드를 호출해야 하며, 그 이후에 네트워크로 추가 패킷을 전송해야 할 수도 있습니다:

// 타임아웃 만료, 이를 처리합니다.
conn.on_timeout();
// 타임아웃 이후 필요에 따라 더 많은 패킷을 전송합니다.
...

네트워크에서 단기적인 혼잡(Congestion)과 손실을 유발할 수 있는 패킷 버스트(Packet bursts)를 방지하기 위해, 애플리케이션은 나가는 패킷의 전송 속도를 조절(Pacing)하는 것이 권장됩니다.

quiche는 send() 메서드에 의해 반환되는 SendInfo 구조체의 at 필드를 통해 나가는 패킷에 대한 페이싱 힌트(Pacing hints)를 제공합니다. 이 필드는 특정 패킷이 네트워크로 전송되어야 하는 시점을 나타냅니다.

애플리케이션은 플랫폼 특화 메커니즘(예: Linux의 SO_TXTIME 소켓 옵션)이나 사용자 공간 타이머(User-space timers)와 같은 커스텀 메서드를 통해 패킷 전송을 인위적으로 지연시킴으로써 이러한 힌트를 사용할 수 있습니다.

몇 차례의 상호작용(Back and forth)을 거친 후, 연결은 핸드셰이크(Handshake)를 완료하고 애플리케이션 데이터를 보내거나 받을 준비가 됩니다.

stream_send() 메서드를 사용하여 스트림(Stream)으로 데이터를 보낼 수 있습니다:

if conn.is_established() {
// 핸드셰이크 완료, 스트림 0으로 데이터를 전송합니다.
conn.stream_send(0, b"hello", true)?;
...

애플리케이션은 연결의 readable() 메서드를 사용하여 읽을 수 있는 스트림이 있는지 확인할 수 있으며, 이 메서드는 읽어야 할 데이터가 남아 있는 모든 스트림에 대한 이터레이터(Iterator)를 반환합니다.

그 후 stream_recv() 메서드를 사용하여 읽을 수 있는 스트림으로부터 애플리케이션 데이터를 가져올 수 있습니다:

if conn.is_established() {
// 읽을 수 있는 스트림들을 순회합니다.
for stream_id in conn.readable() {
...

quiche HTTP/3 모듈은 QUIC 전송 프로토콜 위에서 HTTP 요청과 응답을 보내고 받기 위한 고수준 API(High level API)를 제공합니다.

quiche API를 사용하는 방법에 대한 더 완전한 예시를 보려면 [quiche/examples/] 디렉토리를 확인하십시오. 여기에는 C/C++ 애플리케이션에서 quiche를 사용하는 방법에 대한 예시가 포함되어 있습니다 (자세한 내용은 아래를 참조하십시오).

quiche는 Rust API 상단에 얇은 C API를 노출하여, C/C++ 애플리케이션(및 FFI를 통해 C API를 호출할 수 있는 다른 언어들)에 quiche를 더 쉽게 통합할 수 있도록 합니다. C API는 C 언어 자체에 의해 부과되는 제약 사항을 제외하고는 Rust API와 동일한 설계를 따릅니다.

cargo build를 실행하면, Rust 라이브러리와 함께 libquiche.a라는 정적 라이브러리(static library)가 자동으로 빌드됩니다. 이는 완전히 독립적이며 C/C++ 애플리케이션에 직접 링크될 수 있습니다.

FFI API를 활성화하려면 cargo--features ffi를 전달하여 ffi 기능을 활성화해야 함을 유의하십시오 (기본적으로 비활성화되어 있습니다).

quiche를 빌드하려면 Rust 1.88 이상이 필요합니다. 최신 안정 버전의 Rust는 rustup을 사용하여 설치할 수 있습니다.

Rust 빌드 환경이 설정되면, git을 사용하여 quiche 소스 코드를 가져올 수 있습니다:

$ git clone https://github.com/cloudflare/quiche

그 다음 cargo를 사용하여 빌드할 수 있습니다:

$ cargo build --examples

cargo는 테스트 스위트(testsuite)를 실행하는 데에도 사용할 수 있습니다:

$ cargo test

TLS 기반의 QUIC 암호화 핸드셰이크(cryptographic handshake)를 구현하는 데 사용되는 BoringSSL은 quiche에 빌드 및 링크되어야 함을 유의하십시오. 이는 cargo로 빌드할 때 boring-sys 크레이트(crate)에 의해 자동으로 수행되지만, 빌드 과정 중에 cmake 명령어를 사용할 수 있어야 합니다.

Windows에서는 NASM도 필요합니다. BoringSSL 공식 문서에 더 자세한 내용이 나와 있습니다.

대안으로, BORING_BSSL_PATH 환경 변수로 BoringSSL 디렉토리를 설정하여 사용자 정의 BoringSSL 빌드를 사용할 수 있습니다:

$ BORING_BSSL_PATH="/path/to/boringssl" cargo build --examples

Android용(NDK 버전 19 이상, 21 권장) quiche 빌드는 cargo-ndk (v2.0 이상)를 사용하여 수행할 수 있습니다.

먼저 Android Studio를 사용하거나 직접 Android NDK를 설치해야 하며, ANDROID_NDK_HOME 환경 변수를 NDK 설치 경로로 설정해야 합니다. 예시는 다음과 같습니다:

$ export ANDROID_NDK_HOME=/usr/local/share/android-ndk

그 다음, 필요한 Android 아키텍처를 위한 Rust 툴체인 (toolchain)을 다음과 같이 설치할 수 있습니다:

$ 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 <architecture>-p <NDK version> 옵션은 필수 사항입니다.

$ cargo ndk -t arm64-v8a -p 21 -- build --features ffi

더 자세한 정보는 build_android_ndk19.sh를 참조하십시오.

iOS용 quiche를 빌드하려면 다음 사항이 필요합니다:

  • Xcode 커맨드 라인 도구 (command-line tools)를 설치하십시오. Xcode를 통해 설치하거나 다음 명령어를 사용하여 설치할 수 있습니다:

$ xcode-select --install

  • iOS 아키텍처를 위한 Rust 툴체인 (toolchain)을 설치하십시오:

$ 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 이미지를 빌드하려면 단순히 다음 명령어를 실행하십시오:

$ make docker-build

quiche Docker 이미지는 다음 Docker Hub 저장소에서 찾을 수 있습니다:

latest 태그는 quiche master 브랜치가 업데이트될 때마다 업데이트됩니다.

cloudflare/quiche

/usr/local/bin에 설치된 서버와 클라이언트를 제공합니다.

cloudflare/quiche-qns

quic-interop-runner 내에서 quiche를 테스트하기 위한 스크립트를 제공합니다.

Copyright (C) 2018-2019, Cloudflare, Inc.

라이선스에 대해서는 COPYING을 참조하십시오.

AI 자동 생성 콘텐츠

본 콘텐츠는 GitHub Trending Rust (weekly)의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.

원문 바로가기
1

댓글

0