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 - 生态集成