Libevent 的 evhttp 停留在 HTTP/1.1
时代。面对 HTTP/2 的多路复用和 HTTP/3 (QUIC)
的低延迟需求,我们需要引入第三方协议栈。
1. HTTP/2 集成 (nghttp2)
nghttp2 是 C 语言实现的 HTTP/2
核心库,它只负责协议解析和状态维护,不负责 I/O。这正好与负责
I/O 的 Libevent 互补。
1.1. 架构设计
我们将 bufferevent 作为传输层(Transport
Layer)。 * 读数据: 当
bufferevent 读到数据时,将其喂给
nghttp2_session_mem_recv。 *
写数据: 注册 nghttp2 的
send_callback,当协议栈需要发送数据时,调用
bufferevent_write。
1.2. ALPN 协商
HTTP/2 通常运行在 TLS 之上。我们需要在 OpenSSL 握手阶段通过 ALPN (Application-Layer Protocol Negotiation) 协商协议。
// OpenSSL 回调
static int alpn_select_cb(SSL *ssl, const unsigned char **out, unsigned char *outlen,
const unsigned char *in, unsigned int inlen, void *arg) {
// 优先选择 "h2"
if (select_protocol(in, inlen, "h2", out, outlen)) {
return SSL_TLSEXT_ERR_OK;
}
return SSL_TLSEXT_ERR_NOACK;
}
// 在 SSL_CTX 中设置
SSL_CTX_set_alpn_select_cb(ctx, alpn_select_cb, NULL);2. HTTP/3 & QUIC 集成
QUIC 基于 UDP,这改变了 Libevent 的使用方式。
2.1. UDP 事件循环
我们不再使用 bufferevent(它是为 TCP
流设计的),而是直接使用 event_new 监听 UDP
socket 的 EV_READ 事件。
struct event *udp_ev = event_new(base, udp_fd, EV_READ | EV_PERSIST, on_udp_packet, NULL);
event_add(udp_ev, NULL);2.2. 集成 quiche / ngtcp2
以 Cloudflare 的 quiche 为例: 1.
on_udp_packet: recvfrom 读取
UDP 包。 2. Process: 调用
quiche_conn_recv 处理数据包。 3.
Send: 调用 quiche_conn_send
获取待发送数据,通过 sendto 发出。 4.
Timer: QUIC
极其依赖定时器(重传、ACK)。需要根据
quiche_conn_timeout_as_nanos 设置 Libevent
的定时器。
3. 总结
虽然 Libevent 没有内置现代协议支持,但其灵活的
bufferevent 和事件机制使其成为构建 HTTP/2 /
QUIC 服务的绝佳底座。通过集成 nghttp2 或
quiche,我们可以享受到 Reactor
模式带来的高性能,同时拥抱最新的 Web 标准。
上一篇: 05-protocols/evdns.md - 异步 DNS 解析 下一篇: 06-production/ecosystem.md - 生态集成
同主题继续阅读
把当前热点继续串成多页阅读,而不是停在单篇消费。
【Libevent 深度剖析与实战指南】异步 DNS 解析 (evdns)
告别阻塞的 getaddrinfo,使用 Libevent 内置的 evdns 实现高性能异步域名解析。
【Libevent 深度剖析与实战指南】内置 HTTP Server (evhttp)
快速上手 Libevent 内置的 evhttp 模块,构建轻量级 HTTP 服务,并了解其局限性。
【Libevent 深度剖析与实战指南】UDP 通信编程
如何在 Libevent 中处理 UDP 通信。为什么 Bufferevent 不适合 UDP?使用原始 Event 接口实现高性能 UDP 服务。
【Libevent 深度剖析与实战指南】多构建工具链集成 (Build Systems)
告别手写 gcc 命令,详解如何在 Makefile、CMake 和 Bazel 项目中优雅地集成 Libevent。