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

ngx_channel_handler

1 定义

ngx_channel_handler 函数 定义在 ./nginx-1.24.0/src/os/unix/ngx_process_cycle.c
staticvoidngx_channel_handler(ngx_event_t*ev){ngx_int_tn;ngx_channel_tch;ngx_connection_t*c;if(ev->timedout){ev->timedout=0;return;}c=ev->data;ngx_log_debug0(NGX_LOG_DEBUG_CORE,ev->log,0,"channel handler");for(;;){n=ngx_read_channel(c->fd,&ch,sizeof(ngx_channel_t),ev->log);ngx_log_debug1(NGX_LOG_DEBUG_CORE,ev->log,0,"channel: %i",n);if(n==NGX_ERROR){if(ngx_event_flags&NGX_USE_EPOLL_EVENT){ngx_del_conn(c,0);}ngx_close_connection(c);return;}if(ngx_event_flags&NGX_USE_EVENTPORT_EVENT){if(ngx_add_event(ev,NGX_READ_EVENT,0)==NGX_ERROR){return;}}if(n==NGX_AGAIN){return;}ngx_log_debug1(NGX_LOG_DEBUG_CORE,ev->log,0,"channel command: %ui",ch.command);switch(ch.command){caseNGX_CMD_QUIT:ngx_quit=1;break;caseNGX_CMD_TERMINATE:ngx_terminate=1;break;caseNGX_CMD_REOPEN:ngx_reopen=1;break;caseNGX_CMD_OPEN_CHANNEL:ngx_log_debug3(NGX_LOG_DEBUG_CORE,ev->log,0,"get channel s:%i pid:%P fd:%d",ch.slot,ch.pid,ch.fd);ngx_processes[ch.slot].pid=ch.pid;ngx_processes[ch.slot].channel[0]=ch.fd;break;caseNGX_CMD_CLOSE_CHANNEL:ngx_log_debug4(NGX_LOG_DEBUG_CORE,ev->log,0,"close channel s:%i pid:%P our:%P fd:%d",ch.slot,ch.pid,ngx_processes[ch.slot].pid,ngx_processes[ch.slot].channel[0]);if(close(ngx_processes[ch.slot].channel[0])==-1){ngx_log_error(NGX_LOG_ALERT,ev->log,ngx_errno,"close() channel failed");}ngx_processes[ch.slot].channel[0]=-1;break;}}}
ngx_channel_handler 函数 是 Nginx Worker 进程接收 Master 进程控制指令的事件回调函数

2 详解

1 函数签名

staticvoidngx_channel_handler(ngx_event_t*ev)
函数不返回任何值
参数 ngx_event_t *ev 当前被触发的事件 事件驱动框架在检测到文件描述符可读时, 会将该文件描述符对应的 ngx_event_t 对象指针传递给注册的回调函数。

2 逻辑流程

1 局部变量 2 超时检查 3 读取并处理数据

1 局部变量
{ngx_int_tn;ngx_channel_tch;ngx_connection_t*c;

2 超时检查
if(ev->timedout){ev->timedout=0;return;}
检查事件是否因超时触发,而非真正的 I/O 就绪 若 ev->timedout 为真, 表示该事件是在定时器到期后被强行调用的, 此时通道上可能并没有数据。 将超时标志清零后直接返回,不执行任何读取操作。

3 读取并处理数据
c=ev->data;ngx_log_debug0(NGX_LOG_DEBUG_CORE,ev->log,0,"channel handler");
#1 从事件对象中取出关联的 ngx_connection_t 结构。 在通道初始化时(ngx_add_channel_event),会将连接对象指针赋值给 ev->data #2 如果编译时开启了 --with-debug,则输出一条调试日志

for(;;){
无限循环,尝试一次性读取通道中所有待处理的消息 通道是流式 socketpair,可能一次读事件到达时,内核缓冲区中积累了多条消息。 循环读取直到返回 NGX_AGAIN(无数据)或发生错误。

n=ngx_read_channel(c->fd,&ch,sizeof(ngx_channel_t),ev->log);
调用 Nginx 封装的通道读取函数, 从文件描述符 c->fd 中读取一条完整的 ngx_channel_t 消息。

ngx_log_debug1(NGX_LOG_DEBUG_CORE,ev->log,0,"channel: %i",n);
输出一条调试日志

if(n==NGX_ERROR){if(ngx_event_flags&NGX_USE_EPOLL_EVENT){ngx_del_conn(c,0);}ngx_close_connection(c);return;}
判断是否发生致命错误 如果当前使用的是 epoll 事件模型, 从 epoll 监听集合中删除该文件描述符的监听事件。 关闭 c->fd 文件描述符, 并回收 ngx_connection_t 结构体到连接池 return:退出函数,因为连接已关闭,后续循环无意义

if(ngx_event_flags&NGX_USE_EVENTPORT_EVENT){if(ngx_add_event(ev,NGX_READ_EVENT,0)==NGX_ERROR){return;}}if(n==NGX_AGAIN){return;}ngx_log_debug1(NGX_LOG_DEBUG_CORE,ev->log,0,"channel command: %ui",ch.command);
为 Solaris 的 Event Port 事件模型

switch(ch.command){
根据消息中的 command 字段执行对应的操作

caseNGX_CMD_QUIT:ngx_quit=1;break;
设置全局变量 ngx_quit 为 1。 发送方: 通常由 master 进程 在收到 SIGQUIT 信号后,通过通道发送给所有 worker 进程 通知 worker 进程 退出

caseNGX_CMD_TERMINATE:ngx_terminate=1;break;
设置全局变量 ngx_terminate 为 1 master 进程通知 worker 进程 终止
caseNGX_CMD_REOPEN:ngx_reopen=1;break;
设置全局变量 ngx_reopen 为 1 master 进程通知 worker 进程 reopen 日志文件 实现日志轮转

caseNGX_CMD_OPEN_CHANNEL:ngx_log_debug3(NGX_LOG_DEBUG_CORE,ev->log,0,"get channel s:%i pid:%P fd:%d",ch.slot,ch.pid,ch.fd);ngx_processes[ch.slot].pid=ch.pid;ngx_processes[ch.slot].channel[0]=ch.fd;break;
新启动了一个 worker,master 进程通知其他已有进程 关于新进程的信息, ch.slot 新 worker 进程在进程管理表中的槽位 ch.pid 新 worker 进程的 pid ch.fd 与新 worker 进程通信的通道的文件描述符 将以上信息记录到当前进程的 进程管理表中

caseNGX_CMD_CLOSE_CHANNEL:ngx_log_debug4(NGX_LOG_DEBUG_CORE,ev->log,0,"close channel s:%i pid:%P our:%P fd:%d",ch.slot,ch.pid,ngx_processes[ch.slot].pid,ngx_processes[ch.slot].channel[0]);if(close(ngx_processes[ch.slot].channel[0])==-1){ngx_log_error(NGX_LOG_ALERT,ev->log,ngx_errno,"close() channel failed");}ngx_processes[ch.slot].channel[0]=-1;break;}}}
一个 worker 进程A结束了 master 进程发送命令通知其他进程 关闭与进程A通信的通道 输出 log 关闭与 进程A 通信的通道文件描述符 将进程表中的该通道描述符标记为 -1,表示已失效
http://www.jsqmd.com/news/688463/

相关文章:

  • 中小企业短期靠外包,长期必须培养懂业务的AI核心人才。
  • CSS如何控制placeholder文字的颜色_使用--placeholder伪元素
  • Fluent自然对流模拟避坑指南:操作温度与密度设置详解(附Gr/Re判断标准)
  • 告别玄学调试:用逻辑分析仪抓波形,根治STM32 SDIO的‘时好时坏’问题
  • 键盘控制鼠标终极指南:用Mouseable彻底改变你的工作方式
  • Valorant DirectX 11崩溃稳定教程:更新后闪退进不去?
  • AI大模型搭建从入门到实战:硬件选型与部署指南
  • OpenBoardView:免费开源.brd文件查看器的完整使用指南
  • 免费开源AMD Ryzen处理器终极调试指南:SMUDebugTool完整教程
  • 苏州来财物资回收:靠谱的苏州废金属回收排名 - LYL仔仔
  • YOLO26火箭检测:箭体mAP50=0.973,火焰0.966,三类航天目标识别(2.4万张数据集)(项目源码+数据集+模型权重+UI界面+python+深度学习+远程环境部署)
  • PSoC 4100T Plus微控制器:低功耗与电容传感技术解析
  • DDrawCompat终极指南:让老游戏在现代Windows上流畅运行的完整教程
  • OpenBoardView:完全免费的.brd电路板文件查看终极指南
  • 虚拟机相关
  • 车载开发团队最后窗口期:VSCode 2026正式版适配截止日倒计时47天——附官方未公开的CI/CD车载流水线模板
  • 为什么FFM在工业界推荐系统中‘效果不咋地’?深入聊聊它的时间复杂度和适用场景
  • YOLO26变电站液体泄露红外检测系统(项目源码+5035张YOLO数据集+模型权重+UI界面+python+深度学习+远程环境部署)
  • Topit:基于ScreenCaptureKit的macOS窗口置顶解决方案
  • 如何在3分钟内为视频添加专业字幕:开源工具终极指南
  • 别只盯着JSON了!聊聊RestTemplate处理那些“非主流”Content-Type的实战经验
  • 2025届学术党必备的五大降重复率助手推荐榜单
  • Qt6实战:用QLocalSocket在Windows和Linux上实现桌面应用间通信(附完整代码)
  • NeRF背后的基石:深入浅出聊聊INR(隐式神经表示)为什么是3D重建的未来
  • 计算机毕业设计:Python股票数据分析与ARIMA预测系统 Flask框架 ARIMA 数据分析 可视化 大数据 大模型(建议收藏)✅
  • 如何免费快速将网页小说转换为EPUB电子书:WebToEpub完整教程
  • WinUtil:基于声明式配置的Windows系统优化与自动化管理架构
  • 2025届毕业生推荐的五大降AI率助手推荐
  • 从波形图看懂AHB协议:用Synopsys VIP实测SINGLE、INCR、WRAP突发传输
  • 小程序富文本组件mp-html:打破微信原生限制的终极解决方案