Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1156949
  • 博文数量: 181
  • 博客积分: 4968
  • 博客等级: 上校
  • 技术积分: 1867
  • 用 户 组: 普通用户
  • 注册时间: 2008-01-13 21:52
文章分类

全部博文(181)

文章存档

2015年(2)

2013年(6)

2012年(22)

2011年(41)

2010年(27)

2009年(51)

2008年(32)

我的朋友

分类: 系统运维

2011-11-09 14:20:28

Nginx ngx_epoll_module模块分析(一)

Nginx的模块是被静态编译到Web Server里面的,因为Nginx的代码量也就十万行左右,编译并不需要多少时间;另外Nginx支持代码热切换,所以这并不是什么问题。Nginx模块开发同Apache非常类似,我想Nginx的作者应该非常精通Aapche吧。

默认情况下,Nginx包括如下模块(在objs/ngx_modules.c目录下)

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
ngx_module_t *ngx_modules[] = {
    &ngx_core_module,
    &ngx_errlog_module,
    &ngx_conf_module,
    &ngx_events_module,
    &ngx_event_core_module,
    &ngx_rtsig_module,
    &ngx_epoll_module,
    &ngx_http_module,
    &ngx_http_core_module,
    &ngx_http_log_module,
    &ngx_http_upstream_module,
    &ngx_http_static_module,
    &ngx_http_autoindex_module,
    &ngx_http_index_module,
    &ngx_http_auth_basic_module,
    &ngx_http_access_module,
    &ngx_http_limit_zone_module,
    &ngx_http_limit_req_module,
    &ngx_http_geo_module,
    &ngx_http_map_module,
    &ngx_http_referer_module,
 
    &ngx_http_map_module,
    &ngx_http_referer_module,
    &ngx_http_rewrite_module,
    &ngx_http_proxy_module,
    &ngx_http_fastcgi_module,
    &ngx_http_memcached_module,
    &ngx_http_empty_gif_module,
    &ngx_http_browser_module,
    &ngx_http_upstream_ip_hash_module,
    &ngx_http_write_filter_module,
    &ngx_http_header_filter_module,
    &ngx_http_chunked_filter_module,
    &ngx_http_range_header_filter_module,
    &ngx_http_gzip_filter_module,
    &ngx_http_postpone_filter_module,
    &ngx_http_charset_filter_module,
    &ngx_http_ssi_filter_module,
    &ngx_http_userid_filter_module,
    &ngx_http_headers_filter_module,
    &ngx_http_copy_filter_module,
    &ngx_http_range_body_filter_module,
    &ngx_http_not_modified_filter_module,
    NULL
};

我一直很好奇Nginx如何使用epoll,所以看了看epoll相关的代码。epoll模块结构非常之简单,通过它可以看到Nginx一个模块应该是什么样子的,但是epoll做的事情确实Nginx的一个核心所在,它源源不断地提供各种事件驱动程序。

epoll模块只有一个参数,那就是指定epoll_wait的events参数。所以它的conf结构体非常简单:

1
2
3
typedef struct {
  ngx_uint_t  events;
} ngx_epoll_conf_t;

epoll的ngx_epoll_create_conf和ngx_epoll_init_conf都非常简单,只是在初始化上面这个ngx_epoll_conf_t结构体。

ngx_epoll_module的定义如下:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
ngx_module_t  ngx_epoll_module = {
  NGX_MODULE_V1,
  &ngx_epoll_module_ctx,               /* module context */
  ngx_epoll_commands,                  /* module directives */
  NGX_EVENT_MODULE,                    /* module type */
  NULL,                                /* init master */
  NULL,                                /* init module */
  NULL,                                /* init process */
  NULL,                                /* init thread */
  NULL,                                /* exit thread */
  NULL,                                /* exit process */
  NULL,                                /* exit master */
  NGX_MODULE_V1_PADDING
};

可以看出ngx_epoll_module 的类型是NGX_EVENT_MODULE,它属于ngx_events_module的子模块,而ngx_events_module又是ngx_core_module的子模块。这种层次关系决定了读取配置的顺序,模块的初始化是一个递归的关系。比如ngx_core_module初始化ngx_events_module,ngx_events_module就必须负责初始化ngx_epoll_module。

ngx_conf_parse这个函数先使用ngx_conf_read_token读取配置数据,然后再使用ngx_conf_handler找到合适的模块,并循环调用它的commands数组中的每个函数。因为ngx_epoll_commands只有一个ngx_conf_set_num_slot函数。

01
02
03
04
05
06
07
08
09
10
11
12
13
static ngx_command_t  ngx_epoll_commands[] = {
 
    { ngx_string("epoll_events"),
      //该函数带有一个参数
      NGX_EVENT_CONF|NGX_CONF_TAKE1,
      ngx_conf_set_num_slot,
      0,
      offsetof(ngx_epoll_conf_t, events),
      NULL },
 
      //必须以ngx_null_command结尾,否则循环会出错
      ngx_null_command
};

Nginx有很多这样的slot函数,这个slot实现很简单,代码如下:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
char *
ngx_conf_set_num_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
    char  *p = conf;
 
    ngx_int_t        *np;
    ngx_str_t        *value;
    ngx_conf_post_t  *post;
 
    np = (ngx_int_t *) (p + cmd->offset);
 
    if (*np != NGX_CONF_UNSET) {
        return "is duplicate";
    }
 
    value = cf->args->elts;
 
    //第一个位置是参数的名字,第二个是参数值
    //比如events 256;
    //value={{6, "event"}, {3, "256"}}
    *np = ngx_atoi(value[1].data, value[1].len);
    if (*np == NGX_ERROR) {
        return "invalid number";
    }
 
    //不知道这个post是用来做什么的
    if (cmd->post) {
        post = cmd->post;
        return post->post_handler(cf, post, np);
    }
 
    return NGX_CONF_OK;
}

ngx_epoll_moduled的create_conf和init_conf也都非常之简单,create_conf负责在内存池中申请一个ngx_epoll_conf_t结构体,init_conf则判断结构体events这个成员变量是否被初始化过了,如果没有的话就将其设置成512。

ngx_epoll_module的配置虽然很简单,但是它要做的事情却不少,看看它的ctx结构体就知道了。

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
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 */
    }
};

呵呵,感觉讲得乱七八糟的,只有看源代码才能理解个中关系。Nginx是一个精品程序,值得细细品味。自己才刚刚起步而已,加油啊~

阅读(2223) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~