注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

逍遥子 曰:

得失失得 何必患得患失 舍得得舍 不妨不舍不得

 
 
 

日志

 
 

[原]Nginx的主要函数调用关系分析  

2017-07-10 14:51:23|  分类: 分布式-服务器相 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

感觉上次写的:

http://houjixin.blog.163.com/blog/static/3562841020172283654952/

这篇总结没把Nginx最主要的函数调用关系说清楚,因此,这次又重新组织了一下,以更简单的方式描述Nginx中如何从main函数开始,到创建各个进程,然后当有客户端连入进来时如何进行消息读取,这篇总结还未涉及到对业务流程的处理,例如对http请求的处理等。

Nginx支持epoll、select、kqueue等不同操作系统下的各种IO多路复用方式,本文以epoll为例分析Nginx是如何实现在一套处理流程中同时兼容各种不同的IO多路复用方式?关于IO多路复用相关的描述可参考:http://blog.csdn.net/houjixin/article/details/27662489

几乎所有的服务器程序的工作模式都是:

l     初始化一些参数;

l     开启监听socket;

l     在主线程的死循环(一般都是死循环)中对监听socket和业务socket进行IO状态监控(IO多路复用),并对IO进行处理;

Nginx也不例外,它的主要工作模式是多进程模式,那么它的工作方式也是类似的。只不过是它的死循环被分散到了各个工作进程中。这里将按照一般服务器程序的工作顺序从main函数切入,逐步深入,并对各个流程进行分析。

mian函数入口的主流程调用关系如下图所示:


主流程的函数执行顺序

各函数的执行顺序说明:

(1)Main函数在文件:src\core\nginx.c中;

(2)核心数据结构 ngx_cycle_t(ngx_cycle_s)存储了Nginx的核心数据结构,包括内存池、日志等信息,nginx几乎所有的操作都围绕该数据结构进行;

(3)打开监听socket

函数调用关系

 main=> ngx_init_cycle=>ngx_open_listening_sockets

(4)创建工作进程

在main函数的最后,调用了主循环处函数:ngx_master_process_cycle或ngx_single_process_cycle中,

(5)主处理流程:ngx_master_process_cycle,在该函数中又调用了ngx_start_worker_processes函数来创建并启动工作进程;

(6)在ngx_start_worker_processes中,在该函数中调用了ngx_spawn_process创建工作进程,工作进程所执行的代码为处理函数ngx_worker_process_cycle;

(7)工作进程主处理函数:ngx_worker_process_cycle,在该函数中死循环调用:ngx_process_events_and_timers进行事件处理;

(8)在函数ngx_process_events_and_timers中,调用了宏ngx_process_events对事件进行处理,需要特别注意该宏, nginx通过它实现了对不同操作系统下各种IO复用方式进行统一处理,这一过程将会在下面详细描述。

(9)宏ngx_process_events被定义为:ngx_event_actions.process_events;其中全局变量ngx_event_actions里保存了处理事件的所有函数指针,ngx_event_action在文件ngx_event.c中被定义为ngx_event_actions_t类型。

(10)ngx_event_actions的类型为:ngx_event_actions_t的全局变量,定义在文件ngx_event.c中,类型ngx_event_actions_t定义形式为:

typedefstruct {

    ngx_int_t (*add)(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags);

    ngx_int_t (*del)(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags);

    ngx_int_t (*enable)(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags);

    ngx_int_t (*disable)(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags);

    ngx_int_t (*add_conn)(ngx_connection_t *c);

    ngx_int_t (*del_conn)(ngx_connection_t *c, ngx_uint_t flags);

    ngx_int_t (*notify)(ngx_event_handler_pt handler);

    ngx_int_t (*process_events)(ngx_cycle_t *cycle, ngx_msec_t timer,

                   ngx_uint_t flags);

    ngx_int_t (*init)(ngx_cycle_t *cycle, ngx_msec_t timer);

    void      (*done)(ngx_cycle_t *cycle);

} ngx_event_actions_t;

这样在Nginx中,全局变量ngx_event_actions里保存了抽象出来的add、del、enable等事件操作函数。

(3)对于Nginx所支持的每种IO复用类型,例如:epoll、poll、kqueue等,它们都会定义自己的处理函数;各IO复用模式的操作函数指针被放在结构体类型ngx_event_module_t中,其定义为:

typedefstruct {

    ngx_str_t              *name;

    void                 *(*create_conf)(ngx_cycle_t*cycle);

    char                 *(*init_conf)(ngx_cycle_t*cycle, void *conf);

    ngx_event_actions_t     actions;

}ngx_event_module_t;

(4)对于epoll,它在文件ngx_epoll_module.c定义了自己的结构体变量:

ngx_event_module_t ngx_epoll_module_ctx

在定义的同时,也给成员ngx_event_actions_tactions赋值了全部的事件操作函数指针,如下图所示:

ngx_event_module_t  ngx_epoll_module_ctx = {

    &epoll_name,

    ngx_epoll_create_conf,               /* create configuration */

    ngx_epoll_init_conf,                 /* init configuration */

    {

        ngx_epoll_add_event,             /* add an event */

        ngx_epoll_del_event,             /* delete an event */

        ngx_epoll_add_event,             /* enable an event */

        ngx_epoll_del_event,             /* disable an event */

        ngx_epoll_add_connection,        /* add an connection */

        ngx_epoll_del_connection,        /* delete an connection */

#if(NGX_HAVE_EVENTFD)

        ngx_epoll_notify,                /* trigger a notify */

#else

        NULL,                            /* trigger a notify */

#endif

        ngx_epoll_process_events,        /* process the events */

        ngx_epoll_init,                  /* init the events */

        ngx_epoll_done,                  /* done the events */

    }

};

可以看到诸如处理事件的函数指针ngx_epoll_process_events等等一系列的事件操作函数指针;

(5)在epoll的ngx_epoll_init函数中将所定义epoll的全部处理函数指针ngx_epoll_module_ctx.actions赋值给该全局变量ngx_event_actions,如下所示:

ngx_event_actions= ngx_epoll_module_ctx.actions;

从而,我们前面重点关注的宏ngx_process_events也就被赋予了操作epoll的具体函数指针。

(6)以事件处理函数指针ngx_epoll_process_events为例,可以看到,在该函数中:

l  调用epoll_wait等待epoll的读事件的到来;

l  Epoll_wait返回之后,通过一个for循环处理所有就绪的socket;

l  如果socket有数据要读,则执行:rev->handler(rev)进行数据读取;如果有socket有数据要写,则执行:wev->handler(wev)进行数据写入;

  评论这张
 
阅读(61)| 评论(0)
推荐 转载

历史上的今天

在LOFTER的更多文章

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017