ngx_create_listening

张开发
2026/4/7 21:34:47 15 分钟阅读

分享文章

ngx_create_listening
1 定义ngx_create_listening 函数 定义在 ./nginx-1.24.0/src/core/ngx_connection.cngx_listening_t*ngx_create_listening(ngx_conf_t*cf,structsockaddr*sockaddr,socklen_tsocklen){size_tlen;ngx_listening_t*ls;structsockaddr*sa;u_char text[NGX_SOCKADDR_STRLEN];lsngx_array_push(cf-cycle-listening);if(lsNULL){returnNULL;}ngx_memzero(ls,sizeof(ngx_listening_t));sangx_palloc(cf-pool,socklen);if(saNULL){returnNULL;}ngx_memcpy(sa,sockaddr,socklen);ls-sockaddrsa;ls-socklensocklen;lenngx_sock_ntop(sa,socklen,text,NGX_SOCKADDR_STRLEN,1);ls-addr_text.lenlen;switch(ls-sockaddr-sa_family){#if(NGX_HAVE_INET6)caseAF_INET6:ls-addr_text_max_lenNGX_INET6_ADDRSTRLEN;break;#endif#if(NGX_HAVE_UNIX_DOMAIN)caseAF_UNIX:ls-addr_text_max_lenNGX_UNIX_ADDRSTRLEN;len;break;#endifcaseAF_INET:ls-addr_text_max_lenNGX_INET_ADDRSTRLEN;break;default:ls-addr_text_max_lenNGX_SOCKADDR_STRLEN;break;}ls-addr_text.datangx_pnalloc(cf-pool,len);if(ls-addr_text.dataNULL){returnNULL;}ngx_memcpy(ls-addr_text.data,text,len);#if!(NGX_WIN32)ngx_rbtree_init(ls-rbtree,ls-sentinel,ngx_udp_rbtree_insert_value);#endifls-fd(ngx_socket_t)-1;ls-typeSOCK_STREAM;ls-backlogNGX_LISTEN_BACKLOG;ls-rcvbuf-1;ls-sndbuf-1;#if(NGX_HAVE_SETFIB)ls-setfib-1;#endif#if(NGX_HAVE_TCP_FASTOPEN)ls-fastopen-1;#endifreturnls;}ngx_create_listening 函数的作用是 在 Nginx 配置解析阶段 将 listen 指令解析出的网络地址信息实例化为 ngx_listening_t 结构体 并注册到全局监听列表中为后续统一创建实际 socket 做数据准备2 详解1 函数签名ngx_listening_t*ngx_create_listening(ngx_conf_t*cf,structsockaddr*sockaddr,socklen_tsocklen)返回值 成功时返回新创建并初始化完成的 ngx_listening_t 对象指针。 失败时返回 NULL参数 ngx_conf_t *cf 指向配置解析上下文 struct sockaddr *sockaddr 传入的需要监听的地址信息 socklen_t socklen 前一个参数的 地址结构的实际字节长度2 逻辑流程1 局部变量 2 创建监听管理对象 3 设置结构体的各个字段 4 返回监听管理对象指针1 局部变量{size_tlen;ngx_listening_t*ls;structsockaddr*sa;u_char text[NGX_SOCKADDR_STRLEN];2 创建监听管理对象lsngx_array_push(cf-cycle-listening);if(lsNULL){returnNULL;}ngx_memzero(ls,sizeof(ngx_listening_t));#1 向 Nginx 全局的“监听数组”cycle-listening 中追加一个空元素 并返回指向该新元素的指针赋值给局部变量 ls。 #2 将新追加的 ngx_listening_t 结构体所占内存区域全部清零每个字节设为 0。3 设置结构体的各个字段sangx_palloc(cf-pool,socklen);if(saNULL){returnNULL;}ngx_memcpy(sa,sockaddr,socklen);#1 从配置解析阶段的内存池 cf-pool 中分配一块大小为 socklen 字节的内存 并将指向这块内存的指针赋值给局部变量 sa。 #2 将传入的 sockaddr 指针所指向的 socklen 字节数据 完整拷贝到新分配的 sa 内存中 为 sockaddr 内容创建一个独立的副本 而不是直接保存传入的 sockaddr 指针ls-sockaddrsa;ls-socklensocklen;将之前分配并拷贝好的套接字地址结构及其长度 赋值给监听管理对象 ls 的对应成员使 ls 正式拥有完整的地址信息。lenngx_sock_ntop(sa,socklen,text,NGX_SOCKADDR_STRLEN,1);ls-addr_text.lenlen;将二进制套接字地址 sa 转换为人类可读的字符串形式 并将该字符串存入缓冲区 text 中同时返回实际写入的字符串长度不含终止符switch(ls-sockaddr-sa_family){#if(NGX_HAVE_INET6)caseAF_INET6:ls-addr_text_max_lenNGX_INET6_ADDRSTRLEN;break;#endif#if(NGX_HAVE_UNIX_DOMAIN)caseAF_UNIX:ls-addr_text_max_lenNGX_UNIX_ADDRSTRLEN;len;break;#endifcaseAF_INET:ls-addr_text_max_lenNGX_INET_ADDRSTRLEN;break;default:ls-addr_text_max_lenNGX_SOCKADDR_STRLEN;break;}根据监听地址的协议族sa_family 设置监听对象 ls 的 addr_text_max_len 字段地址文本缓冲区的最大所需长度 并且在 Unix 域套接字的情况下对 len 进行修正len。 addr_text_max_len 用于指示将来存储该地址字符串时 缓冲区应预留的最大字符数包括可能的端口、括号等格式化字符。#1 将 addr_text_max_len 设为适合 IPv6 地址文本的最大长度 NGX_INET6_ADDRSTRLEN Nginx 定义的宏表示 IPv6 地址字符串表示的最大长度#2 设置最大长度为 Unix 域路径的最大值 并调整当前实际长度 len 使其增加 1。 NGX_UNIX_ADDRSTRLEN Nginx 定义的 Unix 域套接字路径最大长度 len 增加之前通过 ngx_sock_ntop 得到的地址文本长度。 为什么要 len 对于 Unix 域套接字ngx_sock_ntop 返回的 len 通常只是路径字符串的长度不包含终止符#3 将 addr_text_max_len 设为适合 IPv4 地址文本的最大长度 NGX_INET_ADDRSTRLEN Nginx 定义的 IPv4 地址字符串最大长度#4 默认分支 如果遇到未知的地址族 则使用一个通用最大长度 NGX_SOCKADDR_STRLEN通常定义为足够容纳任何地址的较大值) 保证 addr_text_max_len 总是被赋予一个合理值避免未初始化。ls-addr_text.datangx_pnalloc(cf-pool,len);if(ls-addr_text.dataNULL){returnNULL;}ngx_memcpy(ls-addr_text.data,text,len);为监听对象 ls 的地址文本字符串addr_text.data分配恰好能容纳 len 字节的内存 并将之前生成的地址文本存放在临时缓冲区 text 中拷贝到这块内存中 完成地址文本的持久化存储。#if!(NGX_WIN32)ngx_rbtree_init(ls-rbtree,ls-sentinel,ngx_udp_rbtree_insert_value);#endif这段代码 是 Nginx 为 UDP 无连接协议实现用户态会话跟踪 的核心初始化逻辑。 它通过在监听结构体中嵌入一棵红黑树 将“无状态”的 UDP 数据流抽象为“有状态”的会话模型。 会话状态容器初始化 为当前监听端口创建一棵空的红黑树 用于动态记录该端口上的 UDP “伪连接”源 IP:端口 ↔ 目的 IP:端口。 平台差异化屏蔽 通过 #if !(NGX_WIN32) 排除 Windows 平台 仅在该机制完整支持且架构匹配的类 Unix 系统上编译。 为后续事件循环提供查找基石 初始化后Worker 进程在收到 UDP 数据包时 可通过此树快速匹配会话节点ls-fd(ngx_socket_t)-1;ls-typeSOCK_STREAM;ls-backlogNGX_LISTEN_BACKLOG;ls-rcvbuf-1;ls-sndbuf-1;#if(NGX_HAVE_SETFIB)ls-setfib-1;#endif#if(NGX_HAVE_TCP_FASTOPEN)ls-fastopen-1;#endif对 ngx_listening_t 结构体中尚未设置的关键成员进行默认值初始化 确保监听对象处于已知、安全的状态4 返回监听管理对象指针returnls;}

更多文章