
Fluent-Bit 内置 nghttp2深入理解 nghttp2_session_get_local_settings 的确认语义与源码实现【免费下载链接】fluent-bitFast and Lightweight Logs, Metrics and Traces processor for Linux, BSD, OSX and Windows项目地址: https://gitcode.com/GitHub_Trending/fl/fluent-bit本文以 Fluent-Bit 仓库内嵌的 nghttp2-1.65.0 库中nghttp2_session_get_local_settings的 API 参考文档为主线完整讲解该函数的原型与返回值语义并结合 nghttp2 的nghttp2_settings_id枚举、会话数据结构、SETTINGS/SETTINGS ACK 握手流程与单元测试说明本地端点参数值何时被对端确认这一核心概念最后对照 Fluent-Bit 的 HTTP/2 客户端与 HTTP 服务器源码展示 SETTINGS 帧提交的实际调用方式。读完本文你将掌握如何在 HTTP/2 库中正确读取已被对端确认的本地 SETTINGS 值并理解它与默认值、nghttp2_session_get_remote_settings的区别。一、函数原型与返回语义nghttp2 官方 API 参考文档位于 nghttp2_session_get_local_settings.rst其中给出的定义非常凝练#include nghttp2/nghttp2.h uint32_t nghttp2_session_get_local_settings( nghttp2_session *session, nghttp2_settings_id id);文档原文的语义说明是Returns the value of SETTINGSidof local endpoint acknowledged by the remote endpoint.即返回本地端点的 SETTINGSid值且该值已被远端端点确认acknowledged。id必须是nghttp2_settings_id枚举中定义的某个值。这句话看似简单但包含了 HTTP/2 协议中一个容易混淆的关键点local settings指的是本端通过 SETTINGS 帧发送给对端的参数例如本端允许的最大并发流数、本端初始流控窗口大小acknowledged by the remote endpoint指的是对端已经用SETTINGS ACK 帧确认收到这些参数。因此在确认完成之前读取到的本地参数仍然是库内部的默认值而不是你通过nghttp2_submit_settings()提交的新值。这一点在 nghttp2 的单元测试中被明确验证nghttp2_session_test.c 中的注释直接写明/* before receiving SETTINGS ACK, local settings have still default values */ assert_uint32(NGHTTP2_DEFAULT_MAX_CONCURRENT_STREAMS, , nghttp2_session_get_local_settings( session, NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS));测试随后手动触发nghttp2_session_on_settings_received接收一个 SETTINGS ACK 帧之后断言值即变为提交时的新值assert_uint32(50, , nghttp2_session_get_local_settings( session, NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS)); assert_uint32(16 * 1024, , nghttp2_session_get_local_settings( session, NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE));这段测试完整演示了提交 → 等待 ACK → 值切换为确认值的全过程是理解本函数语义的最佳实证。二、id 的全部合法取值nghttp2_settings_id 枚举文档要求id必须是nghttp2_settings_id中的值。该枚举在 nghttp2.h 中定义了 8 个 SETTINGS 参数枚举值数值对应 HTTP/2 参数NGHTTP2_SETTINGS_HEADER_TABLE_SIZE0x01HPACK 动态表大小NGHTTP2_SETTINGS_ENABLE_PUSH0x02是否启用服务器推送NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS0x03最大并发流数NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE0x04连接级初始窗口大小NGHTTP2_SETTINGS_MAX_FRAME_SIZE0x05最大帧大小NGHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE0x06最大头部块列表大小NGHTTP2_SETTINGS_ENABLE_CONNECT_PROTOCOL0x08启用 CONNECT 协议扩展RFC 8441NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES0x09禁用 RFC 7540 优先级RFC 9218头文件源码注释还提示了一个维护要点新增 SETTINGS 时需要同步更新NGHTTP2_INBOUND_NUM_IV容量说明这 8 个 ID 与库内部 SETTINGS 载荷解析的存储容量是绑定设计的。三、源码实现从枚举分发到会话存储函数声明位于 nghttp2.h#L4062-L4070紧邻其上方的nghttp2_session_get_remote_settings文档说明为返回远端端点通告的 SETTINGS 值——两者成对出现分别读取会话中的两份参数存储。具体实现在 nghttp2_session.c#L7443-L7466uint32_t nghttp2_session_get_local_settings(nghttp2_session *session, nghttp2_settings_id id) { switch (id) { case NGHTTP2_SETTINGS_HEADER_TABLE_SIZE: return session-local_settings.header_table_size; case NGHTTP2_SETTINGS_ENABLE_PUSH: return session-local_settings.enable_push; case NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS: return session-local_settings.max_concurrent_streams; case NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE: return session-local_settings.initial_window_size; case NGHTTP2_SETTINGS_MAX_FRAME_SIZE: return session-local_settings.max_frame_size; case NGHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE: return session-local_settings.max_header_list_size; case NGHTTP2_SETTINGS_ENABLE_CONNECT_PROTOCOL: return session-local_settings.enable_connect_protocol; case NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES: return session-local_settings.no_rfc7540_priorities; } assert(0); abort(); /* if NDEBUG is set */ }从源码结构看有三个值得注意的实现细节纯只读访问函数直接返回session-local_settings结构体中的对应字段无锁、无计算、无副作用因此调用成本极低适合在帧回调中频繁读取。local_settings的结构定义该字段声明在 nghttp2_session.h#L326nghttp2_settings_storage local_settings;与会话中的remote_settings并列存放对应本端参数与对端参数两份独立状态。非法 id 的行为传入枚举之外的值会落入assert(0)并在断言开启时abort()。这是库内部契约调用方必须保证id合法——这也是 API 文档中idmust be one of the values defined in nghttp2_settings_id这一约束的底层依据。local_settings 的生命周期初始化、更新与确认初始化会话创建时nghttp2_session.c#L482调用init_settings()填充协议默认值例如最大并发流默认值定义为 nghttp2_session.h#L103 的NGHTTP2_DEFAULT_MAX_CONCURRENT_STREAMS即0xffffffffu。更新nghttp2_session_update_local_settings()nghttp2_session.c#L4146根据 SETTINGS 帧携带的nghttp2_settings_entry数组逐项写入session-local_settings字段。确认生效测试用例进一步印证收到 SETTINGS ACK 后session-local_settings.initial_window_size等字段才被最终认定为已确认状态在 ACK 之前的窗口内本函数读到的是默认值而非待提交值。四、在 Fluent-Bit 中的实际使用场景Fluent-Bit 在两个位置使用 nghttp2 的 SETTINGS 机制通过nghttp2_submit_settings提交本端参数这正是nghttp2_session_get_local_settings所读取的同一份状态1. HTTP/2 客户端日志/数据发送侧flb_http_client_http2.c#L506-L531 在创建客户端会话nghttp2_session_client_new后立即提交 3 项本地 SETTINGSsession_settings[0].settings_id NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS; session_settings[0].value 1; session_settings[1].settings_id NGHTTP2_SETTINGS_MAX_FRAME_SIZE; session_settings[1].value cfl_sds_alloc(session-parent-parent-temporary_buffer); session_settings[2].settings_id NGHTTP2_SETTINGS_ENABLE_PUSH; session_settings[2].value 0; result nghttp2_submit_settings(session-inner_session, NGHTTP2_FLAG_NONE, session_settings, 3);可以看到 Fluent-Bit 的 HTTP/2 客户端把并发流限制为 1、关闭服务器推送这符合其作为单向数据投递客户端的用途——不需要多路复用并发也不需要服务器主动推送流。从源码结构看当前客户端代码路径主要依赖nghttp2_submit_settings完成本端参数通告尚未直接调用nghttp2_session_get_local_settings读取确认值但该函数为上层在需要感知对端已确认的本地窗口/并发参数时提供了标准入口。2. HTTP 服务器内置 HTTP Server / 指标采集侧flb_http_server_http2.c#L397-L413 在nghttp2_session_server_new之后提交本端 SETTINGSsession_settings[0].settings_id NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS; session_settings[0].value 1; result nghttp2_submit_settings(session-inner_session, NGHTTP2_FLAG_NONE, session_settings, 1);服务器端同样将MAX_CONCURRENT_STREAMS设为 1随后通过nghttp2_session_send发出 SETTINGS 帧启动握手。对这类参数固定、逻辑简单的服务端场景本地 SETTINGS 值在确认前是默认值、确认后可读回这一语义尤其值得注意若上层逻辑需要判断握手是否完成从确认值是否等于提交值入手是一种可行的推断方式这一点属于从源码结构推断nghttp2 文档本身未作此用途的明示。五、使用本函数的实践要点结合 API 文档与源码使用nghttp2_session_get_local_settings时应把握以下要点返回值类型是uint32_t所有 SETTINGS 参数值在 HTTP/2 帧中均为 32 位无符号整数函数不通过返回值指示错误因此不存在错误码分支。区分提交值与确认值在收到对端 SETTINGS ACK 之前读到的是库默认值如最大并发流为0xffffffffu需要感知确认状态时应结合 ACK 帧事件如on_frame_recv回调综合判断。与nghttp2_session_get_remote_settings配对使用前者回答对端确认了我的哪些参数后者回答对端要求我遵守哪些参数例如对端的NGHTTP2_SETTINGS_MAX_FRAME_SIZE决定了你能发出的最大帧长。id 必须合法非法枚举值会触发断言失败属于未定义行为不应在生产路径上依赖。线程与调用时机该函数是对会话结构体的直接字段读取应与会话的读写处于同一线程上下文避免与其他nghttp2_session_*调用产生竞争。小结nghttp2_session_get_local_settings是 nghttp2 会话 API 中读取已被对端确认的本地 SETTINGS 参数的唯一标准入口它以nghttp2_settings_id为索引直接映射到会话内的local_settings存储nghttp2_session.c#L7443-L7466。其真正的技术含量不在函数本身而在 HTTP/2 SETTINGS 握手的时序语义——提交新值后、ACK 之前读到默认值ACK 之后才读到确认值这一点由 nghttp2_session_test.c#L5990-L6016 的测试序列完整佐证。在 Fluent-Bit 中HTTP/2 客户端src/flb_http_client_http2.c与内置 HTTP 服务器src/http_server/flb_http_server_http2.c均围绕同一套 SETTINGS 机制工作本函数为理解这两处 SETTINGS 帧交换提供了完整的语义基准。【免费下载链接】fluent-bitFast and Lightweight Logs, Metrics and Traces processor for Linux, BSD, OSX and Windows项目地址: https://gitcode.com/GitHub_Trending/fl/fluent-bit创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考