当前位置: 首页 > news >正文

ngx_create_listening

1 定义

ngx_create_listening 函数 定义在 ./nginx-1.24.0/src/core/ngx_connection.c
ngx_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];ls=ngx_array_push(&cf->cycle->listening);if(ls==NULL){returnNULL;}ngx_memzero(ls,sizeof(ngx_listening_t));sa=ngx_palloc(cf->pool,socklen);if(sa==NULL){returnNULL;}ngx_memcpy(sa,sockaddr,socklen);ls->sockaddr=sa;ls->socklen=socklen;len=ngx_sock_ntop(sa,socklen,text,NGX_SOCKADDR_STRLEN,1);ls->addr_text.len=len;switch(ls->sockaddr->sa_family){#if(NGX_HAVE_INET6)caseAF_INET6:ls->addr_text_max_len=NGX_INET6_ADDRSTRLEN;break;#endif#if(NGX_HAVE_UNIX_DOMAIN)caseAF_UNIX:ls->addr_text_max_len=NGX_UNIX_ADDRSTRLEN;len++;break;#endifcaseAF_INET:ls->addr_text_max_len=NGX_INET_ADDRSTRLEN;break;default:ls->addr_text_max_len=NGX_SOCKADDR_STRLEN;break;}ls->addr_text.data=ngx_pnalloc(cf->pool,len);if(ls->addr_text.data==NULL){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->type=SOCK_STREAM;ls->backlog=NGX_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 创建监听管理对象
ls=ngx_array_push(&cf->cycle->listening);if(ls==NULL){returnNULL;}ngx_memzero(ls,sizeof(ngx_listening_t));
#1 向 Nginx 全局的“监听数组”cycle->listening 中追加一个空元素, 并返回指向该新元素的指针,赋值给局部变量 ls。 #2 将新追加的 ngx_listening_t 结构体所占内存区域全部清零(每个字节设为 0)。

3 设置结构体的各个字段
sa=ngx_palloc(cf->pool,socklen);if(sa==NULL){returnNULL;}ngx_memcpy(sa,sockaddr,socklen);
#1 从配置解析阶段的内存池 cf->pool 中分配一块大小为 socklen 字节的内存, 并将指向这块内存的指针赋值给局部变量 sa。 #2 将传入的 sockaddr 指针所指向的 socklen 字节数据, 完整拷贝到新分配的 sa 内存中 为 sockaddr 内容创建一个独立的副本, 而不是直接保存传入的 sockaddr 指针

ls->sockaddr=sa;ls->socklen=socklen;
将之前分配并拷贝好的套接字地址结构及其长度, 赋值给监听管理对象 ls 的对应成员,使 ls 正式拥有完整的地址信息。

len=ngx_sock_ntop(sa,socklen,text,NGX_SOCKADDR_STRLEN,1);ls->addr_text.len=len;
将二进制套接字地址 sa 转换为人类可读的字符串形式, 并将该字符串存入缓冲区 text 中,同时返回实际写入的字符串长度(不含终止符)

switch(ls->sockaddr->sa_family){#if(NGX_HAVE_INET6)caseAF_INET6:ls->addr_text_max_len=NGX_INET6_ADDRSTRLEN;break;#endif#if(NGX_HAVE_UNIX_DOMAIN)caseAF_UNIX:ls->addr_text_max_len=NGX_UNIX_ADDRSTRLEN;len++;break;#endifcaseAF_INET:ls->addr_text_max_len=NGX_INET_ADDRSTRLEN;break;default:ls->addr_text_max_len=NGX_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.data=ngx_pnalloc(cf->pool,len);if(ls->addr_text.data==NULL){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->type=SOCK_STREAM;ls->backlog=NGX_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;}
http://www.jsqmd.com/news/604134/

相关文章:

  • IndexTTS 2.0对比实测:零样本克隆与传统训练效果差异
  • Scratch趣味编程:从零打造水果接龙小游戏
  • 基于Matlab Simulink的单相PWM整流器仿真模型:全桥整流,电压电流PI双闭环控制...
  • 智能化 SaaS 招聘系统全解析:核心功能与企业招聘价值
  • ADRV9009网口驱动避坑指南:解决FreeRTOS下LWIP长时间通信宕机问题
  • 效率飙升:快马AI批量处理网址,自动生成打印就绪文档
  • 【自动驾驶C++部署黄金法则】:20年老司机亲授5大避坑指南,90%团队在第3步就翻车?
  • Avantage 6.9.0 XPS数据处理软件免费下载
  • SEO_从零开始,手把手教你做好站内SEO优化(238 )
  • 跑不出密码别怪字典!实战解析Kali Linux中aircrack-ng跑包效率提升的5个关键技巧
  • 事务(transaction)
  • 【Mojo与Python混合编程实战指南】:20年架构师亲授3大无缝接入模式,90%开发者忽略的性能陷阱全曝光
  • 【读书笔记】《理性的非理性》
  • 从仿真到流片:手把手教你写可综合的Verilog task(附真实工程案例)
  • 物流企业如何通过企业级AI Agent优化调度与单据处理?架构师深度评测实在Agent的非侵入式落地路径
  • Python爬虫数据智能分析流水线:PyTorch模型自动化处理实战
  • 【2026 Python原生AOT编译终极指南】:零依赖、亚毫秒启动、生产级瘦身——来自CPython核心组的3项未公开落地规范
  • 配置nanobot的详细教程(已完善)(有错误请指出)谢谢
  • 017篇:录制器的使用:录制一个登录操作
  • DoDAF能力视点(CV)深度解析:从理论基石到卓越实践的体系化构建
  • Python MCP服务器开发模板实战手册(含完整CI/CD流水线与OpenTelemetry集成)
  • 告别繁琐流程,高效获取教育资源的新方式
  • 书匠策AI:论文写作界的“智能导航仪”,带你轻松驶向期刊发表的彼岸
  • Python MCP服务器模板深度拆解(企业级接入SOP首次公开)
  • 从429限流到满速下载:一个HF Token如何解锁Unsloth微调全流程
  • Cursor Pro功能解锁技术探索:设备绑定突破与权限管理实践指南
  • Proteus仿真STM32,CubeMX生成的代码跑不起来?先检查这个时钟频率设置!
  • 从 99.8% 到 14.9%!Paperxie 降 AIGC 神器,本科生论文通关密码
  • 高效Godot资源提取工具:零基础上手与格式转换技巧
  • 为什么你的医疗3D体绘制在NVIDIA A100上仍掉帧?——解析CUDA流同步、纹理缓存对齐与HIP-Clang跨编译器ABI兼容性三大致命盲区