龙空技术网

Nginx源码分析(四)

5岁可以抬头 169

前言:

现时看官们对“nginx源码anzh”大体比较看重,你们都需要知道一些“nginx源码anzh”的相关文章。那么小编也在网摘上搜集了一些有关“nginx源码anzh””的相关内容,希望你们能喜欢,兄弟们一起来了解一下吧!

前面分析了Nginx的基本数据结构,现在看一下功能模块。

Nginx将各功能模块组成一条链,当有请求到达时,请求依次进过这条链上的部分或全部模块进行处理。

线程模型

Nginx使用一个多进程模型来提供服务,一个master进程和多个worker进程。类似的原理可以参见分布式进程。框架如下:

master分管多个work进程。每个worker执行死循环接收来自客户端的请求。死循环由ngx_worker_process_cycle实现。一个请求的简单处理流程如下:

操作系统提供的机制(例如epoll, kqueue等)产生相关的事件接收和处理这些事件,如是接受到数据,则产生更高层的request对象处理request的header和body产生响应,并发送回客户端完成request的处理重新初始化定时器及其他事件

show the code

static voidngx_worker_process_cycle(ngx_cycle_t *cycle, void *data){ ngx_int_t worker = (intptr_t) data; ngx_uint_t i; ngx_connection_t *c; ngx_process = NGX_PROCESS_WORKER; ngx_worker = worker; //设定n个worker进程 ngx_worker_process_init(cycle, worker); ngx_setproctitle("worker process"); for ( ;; ) { //如果进程退出,关闭所有连接 if (ngx_exiting) { c = cycle->connections; for (i = 0; i < cycle->connection_n; i++) { if (c[i].fd != -1 && c[i].idle) { c[i].close = 1; c[i].read->handler(c[i].read); } } //定时器归0 ngx_event_cancel_timers(); //判断timer的红黑树是否为空 if (ngx_event_timer_rbtree.root == ngx_event_timer_rbtree.sentinel) { ngx_worker_process_exit(cycle); } } ngx_process_events_and_timers(cycle); //处理中断信号 if (ngx_terminate) { ngx_worker_process_exit(cycle); } //处理退出信号 if (ngx_quit) { ngx_quit = 0; ngx_setproctitle("worker process is shutting down"); if (!ngx_exiting) { ngx_close_listening_sockets(cycle); ngx_exiting = 1; } } //处理重启log if (ngx_reopen) { ngx_reopen = 0; ngx_reopen_files(cycle, -1); } }}

其中几个关键函数是

ngx_worker_process_init 处理子进程初始化

ngx_process_events_and_timers(cycle)

ngx_worker_process_exit(cycle) 子进程退出

下面来看一下子进程的初始化操作:

全局性的设置,根据全局的配置信息设置执行环境、优先级、限制、setgid、setuid、信号初始化等调用所有模块的钩子init_process

for (i = 0; ngx_modules[i]; i++) { if (ngx_modules[i]->init_process) { if (ngx_modules[i]->init_process(cycle) == NGX_ERROR{ exit(2);  } }}

里面关键的函数是init_process。

关闭不使用的socket,关闭当前worker的channel[0]句柄和其他worker的channel[1]句柄,当前worker会使用其他worker的channel[0]句柄发送消息,使用当前worker的channel[1]句柄监听可读事件

for (n = 0; n < ngx_last_process; n++) { if (ngx_processes[n].pid == -1) { continue; } //跳过当前worker if (n == ngx_process_slot) { continue; } if (ngx_processes[n].channel[1] == -1) { continue; } //关闭其它workers channel[1] if (close(ngx_processes[n].channel[1]) == -1) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, "close() channel failed"); }}//关闭当前worker channel[0]if (close(ngx_processes[ngx_process_slot].channel[0]) == -1) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, "close() channel failed");}
在当前worker的channel[1]句柄监听可读事件
if (ngx_add_channel_event(cycle, ngx_channel, NGX_READ_EVENT,ngx_channel_handler) == NGX_ERROR){ exit(2);}

ngx_add_channel_event把句柄ngx_channel(当前worker的channel[1])上建立的连接的可读事件加入事件监控队列,事件处理函数为ngx_channel_hanlder。当有可读事件的时候,ngx_channel_handler负责处理消息,具体代码可以查看src/os/unix/ngx_process_cycle.c,过程如下:

static voidngx_channel_handler(ngx_event_t *ev){//...for ( ;; ) { //从channe[1]读取消息 n = ngx_read_channel(c->fd, &ch, sizeof(ngx_channel_t), ev->log);  //处理消息命令 switch (ch.command) { case NGX_CMD_QUIT: ngx_quit = 1; break; case NGX_CMD_TERMINATE: ngx_terminate = 1; break; case NGX_CMD_REOPEN: ngx_reopen = 1; break; case NGX_CMD_OPEN_CHANNEL: ngx_processes[ch.slot].pid = ch.pid; ngx_processes[ch.slot].channel[0] = ch.fd; break; case NGX_CMD_CLOSE_CHANNEL: 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; } }}

求波关注,点赞,转发!更多好文章第一时间推送。

标签: #nginx源码anzh