nginx中的事件响应机制(以epoll为例)

来源:互联网 发布:考勤数据 编辑:程序博客网 时间:2024/05/09 05:08

一.nginx中提供的事件驱动如何实现?
在sys/epoll.h中
1、epoll_create函数
函数声明:int epoll_create(int size)
该 函数生成一个epoll专用的文件描述符。它其实是在内核申请一空间,用来存放你想关注的socket fd上是否发生以及发生了什么事件。size就是你在这个epoll fd上能关注的最大socket fd数。随你定好了。只要你有空间。可参见上面与select之不同
2、epoll_ctl函数
函数声明:int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event)
该函数用于控制某个epoll文件描述符上的事件,可以注册事件,修改事件,删除事件。
3、epoll_wait函数
函数声明:int epoll_wait(int epfd,struct epoll_event * events,int maxevents,int timeout)
该函数用于轮询I/O事件的发生;

在ngx_epoll_epoll_module.c中的函数ngx_epoll_add_event等调用以上几个函数来将文件描述符事件添加到epoll事件监听中去(为何在nginx中有一个空的epoll_ctl等函数???)。

那么这个添加的过程是怎么走的呢,nginx如何将文件描述符事件加入到epoll事件监听中去的呢?
如下这样处理
在Ngx_epoll_module.c中定义一个事件处理模块结构

typedef struct {//事件模块 的名称    ngx_str_t              *name;//在解析配置前,这个回调方法用于创建存储配置项参数的结构体    void                 *(*create_conf)(ngx_cycle_t *cycle);//在解析配置项后,init_conf方法会被调用,用以综合处理当前事件模块感兴趣的所有配置项    char                 *(*init_conf)(ngx_cycle_t *cycle, void *conf);//对于事件驱动机制,每个事件模块需要实现的10个抽象方法    ngx_event_actions_t     actions;} ngx_event_module_t;其中ngx_event_actions_t结构体的定义如下:typedef struct {//添加事件方法,负责将感兴趣的事件添加到操作系统提供的事件驱动机制中(如epoll,kqueue)//这样,在事件发生后,可以调用下面的process_events时或取这个事件    ngx_int_t  (*add)(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags);/*删除事件方法,将已存在于事件驱动机制中的事件移除,以后再发生这样的事件调用process_events也无法获取事件*/    ngx_int_t  (*del)(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags);/*启用一个事件,目前事件框架不会调用这个方法,大部分事件驱动模块对于该事件的实现都是与上面的add方法一致*/    ngx_int_t  (*enable)(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags);/*禁用一个事件,目前事件框架不会调用这个方法,大部分事件驱动模块对于该事件的实现都是与上面的del方法一致*/    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  (*process_changes)(ngx_cycle_t *cycle, ngx_uint_t nowait);//在正常的工作中,将通过调用这个函数来处理事件,//在ngx_process_events_and_timers方法中调用,它是处理分发事件的核心    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;

然后用这个类型定义一个变量来添加这些处理函数

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 */        NULL,                            /* process the changes */        ngx_epoll_process_events,        /* process the events */        ngx_epoll_init,                  /* init the events */        ngx_epoll_done,                  /* done the events */    }};

在ngx_event_core_module核心的事件模块中有如下定义

ngx_module_t  ngx_event_core_module = {    NGX_MODULE_V1,    &ngx_event_core_module_ctx,            /* module context */    ngx_event_core_commands,               /* module directives */    NGX_EVENT_MODULE,                      /* module type */    NULL,                                  /* init master */    ngx_event_module_init,                 /* init module */    ngx_event_process_init,                /* init process */    NULL,                                  /* init thread */    NULL,                                  /* exit thread */    NULL,                                  /* exit process */    NULL,                                  /* exit master */    NGX_MODULE_V1_PADDING};

其中ngx_event_process_init函数是在初始化进程时候调用
1.在ngx_event_process_init这个函数中,使用了如下语句
module->actions.init(cycle, ngx_timer_resolution)用这个来调用ngx_epoll_module_ctx 这个结构中定义init来调用ngx_epoll_init这个回调函数
在ngx_epoll_init这个函数中:通过ngx_event_actions = ngx_epoll_module_ctx.actions;将这些回调函数赋给全局变量ngx_event_actions.
2.在ngx_event_process_init这个函数中,还使用ngx_add_event(rev, 0, NGX_IOCP_ACCEPT),通过宏定义#define ngx_add_event ngx_event_actions.add等来将文件描述符的事件加入到epoll事件监听中去。

事件发生后,nginx如何处理事件?
process_events 在epoll模式中所对应的ngx_epoll_process_events函数是事件发生后处理的一个函数
处理过程基本是判断事件类别,如if(revents & EPOLLOUT) && wev->active),再根据不同的消费模块调用不同的处理函数wev->handler。

例如
http模块中,通过ngx_http_commands中设置的ngx_http_block函数
ngx_http_block函数中调用ls->handler = ngx_http_init_connection;设置ngx_listening_s监听的处理函数。
ngx_http_init_connection;函数中再调用rev->handler = ngx_http_init_request; c->write->handler = ngx_http_empty_handler;来设置文件描述符的处理函数,分别是ngx_http_init_request读事件函数和ngx_http_empty_handler写事件函数

在添加ngx_connection_s的文件描述符的事件监听过程,添加之后listening监听的事件是否被一同添加?(如何测试?)

0 0
原创粉丝点击