现在的位置: 首页 > 综合 > 正文

nginx模块分析

2014年07月04日 ⁄ 综合 ⁄ 共 6397字 ⁄ 字号 评论关闭

想要理解nginx服务器的源码,那么首先就必须理解它的模块化的思想,因为nginx是master加worker的方式进行运行的,因而在master进程以及worker进程中都会涉及到许多模块的初始化的地方,例如创建配置,读取配置等。在模块内又会提供许多的回调函数,这样在合适的地方调用这些回调函数就可以了。

首先来看nginx模块化的最基本结构ngx_module_t,它的定义是在Src/Core/Ngx_conf_file.h里面:

#define NGX_MODULE_V1          0, 0, 0, 0, 0, 0, 1
#define NGX_MODULE_V1_PADDING  0, 0, 0, 0, 0, 0, 0, 0

//模块的数据结构定义
struct ngx_module_s {
    ngx_uint_t            ctx_index;   //分类模计数器
    ngx_uint_t            index;     //模块计数器

    ngx_uint_t            spare0;
    ngx_uint_t            spare1;
    ngx_uint_t            spare2;
    ngx_uint_t            spare3;

    ngx_uint_t            version;    //版本

    void                 *ctx;    //该模块的上下文,也就是说指向的是哪一个模块,core或者event或者http或者mail,conf
    ngx_command_t        *commands;  //该模块的命令集,指向一个ngx_command_t结构数组  
    ngx_uint_t            type;   //该模块的种类,为core/event/http/mail中的一种  
   
    ngx_int_t           (*init_master)(ngx_log_t *log);    //初始化master  

    ngx_int_t           (*init_module)(ngx_cycle_t *cycle);    //初始化模块  

    ngx_int_t           (*init_process)(ngx_cycle_t *cycle);    //初始化工作进程的时候调用
    ngx_int_t           (*init_thread)(ngx_cycle_t *cycle);   //初始化线程的时候调用
    void                (*exit_thread)(ngx_cycle_t *cycle);   //退出线程
    void                (*exit_process)(ngx_cycle_t *cycle);   //退出进程

    void                (*exit_master)(ngx_cycle_t *cycle);    //退出master  

    uintptr_t             spare_hook0;
    uintptr_t             spare_hook1;
    uintptr_t             spare_hook2;
    uintptr_t             spare_hook3;
    uintptr_t             spare_hook4;
    uintptr_t             spare_hook5;
    uintptr_t             spare_hook6;
    uintptr_t             spare_hook7;
};

具体每一个域的作用在上面已经标示了出来,nginx会有一个全局的变量ngx_modules用来保存所有的模块,nginx模块分为五种类型,core,event,http,mail以及conf,ctx_index域就是用来保存每个模块相对于自己类型的模块其索引号是多少,这在以后创建以及获取配置是很有用的,因为nginx将配置按照模块的类型进行了分类,例如在Src/Event/Ngx_event.c中就有如下的代码进行event模块的ctx_index域的初始化:

ngx_event_max_module = 0;
    for (i = 0; ngx_modules[i]; i++) {
        if (ngx_modules[i]->type != NGX_EVENT_MODULE) {
            continue;
        }

        ngx_modules[i]->ctx_index = ngx_event_max_module++;  //记录当前事件模块的事件模块分类索引
    }

其余类型的模块的ctx_index的初始化与其实类似的。

另外还有一个非常重要的域,ctx,指的是当前模块的上下文,因为有五种模块的类型,那么就会有五种类型的上下文,指向具体对应的模块。

还有一个commands命令集,nginx的模块都有自定义的一些命令,这些命令将会与配置文件中相应的配置信息对应,每一个命令在源码中都对应着一个ngx_command_t的结构,nginx会在配置文件中将命令读取出来,放到commands数组当中,ngx_command_t的定义也是在Src/Core/Ngx_conf_file.h里面:

struct ngx_command_s {
    ngx_str_t             name;    //命令的名字
    ngx_uint_t            type;   //命令的类型
    char               *(*set)(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);   //命令的回调函数
    ngx_uint_t            conf;
    ngx_uint_t            offset;
    void                 *post;
};


在编译了源码之后,可以在生成的objs目录下面的ngx_modules.c文件内看到导出的所有模块:

00001:
00002: #include <ngx_config.h>
00003: #include <ngx_core.h>
00004:
00005:
00006:
00007: extern ngx_module_t ngx_core_module;
00008: extern ngx_module_t ngx_errlog_module;
00009: extern ngx_module_t ngx_conf_module;
00010: extern ngx_module_t ngx_events_module;
00011: extern ngx_module_t ngx_event_core_module;
00012: extern ngx_module_t ngx_epoll_module;
00013: extern ngx_module_t ngx_http_module;
00014: extern ngx_module_t ngx_http_core_module;
00015: extern ngx_module_t ngx_http_log_module;
00016: extern ngx_module_t ngx_http_upstream_module;
00017: extern ngx_module_t ngx_http_static_module;
00018: extern ngx_module_t ngx_http_autoindex_module;
00019: extern ngx_module_t ngx_http_index_module;
00020: extern ngx_module_t ngx_http_auth_basic_module;
00021: extern ngx_module_t ngx_http_access_module;
00022: extern ngx_module_t ngx_http_limit_zone_module;
00023: extern ngx_module_t ngx_http_limit_req_module;
00024: extern ngx_module_t ngx_http_geo_module;
00025: extern ngx_module_t ngx_http_map_module;
00026: extern ngx_module_t ngx_http_split_clients_module;
00027: extern ngx_module_t ngx_http_referer_module;
00028: extern ngx_module_t ngx_http_rewrite_module;
00029: extern ngx_module_t ngx_http_proxy_module;
00030: extern ngx_module_t ngx_http_fastcgi_module;
00031: extern ngx_module_t ngx_http_uwsgi_module;
00032: extern ngx_module_t ngx_http_scgi_module;
00033: extern ngx_module_t ngx_http_memcached_module;
00034: extern ngx_module_t ngx_http_empty_gif_module;
00035: extern ngx_module_t ngx_http_browser_module;
00036: extern ngx_module_t ngx_http_upstream_ip_hash_module;
00037: extern ngx_module_t ngx_http_stub_status_module;
00038: extern ngx_module_t ngx_http_write_filter_module;
00039: extern ngx_module_t ngx_http_header_filter_module;
00040: extern ngx_module_t ngx_http_chunked_filter_module;
00041: extern ngx_module_t ngx_http_range_header_filter_module;
00042: extern ngx_module_t ngx_http_gzip_filter_module;
00043: extern ngx_module_t ngx_http_postpone_filter_module;
00044: extern ngx_module_t ngx_http_ssi_filter_module;
00045: extern ngx_module_t ngx_http_charset_filter_module;
00046: extern ngx_module_t ngx_http_userid_filter_module;
00047: extern ngx_module_t ngx_http_headers_filter_module;
00048: extern ngx_module_t ngx_http_copy_filter_module;
00049: extern ngx_module_t ngx_http_range_body_filter_module;
00050: extern ngx_module_t ngx_http_not_modified_filter_module;
00051:

这些模块都是在此处用extern进行申明的,而具体的定义则在相应的.c文件当中进行的,例如ngx_epoll_module的申明是在Ngx_epoll_module.c文件中。

同样在生成的objs目录下面的ngx_modules.c文件内可以看到前面提到的全局变量ngx_modules的定义:

00052: ngx_module_t *ngx_modules[] = {
00053:    &ngx_core_module,
00054:    &ngx_errlog_module,
00055:    &ngx_conf_module,
00056:    &ngx_events_module,
00057:    &ngx_event_core_module,
00058:    &ngx_epoll_module,
00059:    &ngx_http_module,
00060:    &ngx_http_core_module,
00061:    &ngx_http_log_module,
00062:    &ngx_http_upstream_module,
00063:    &ngx_http_static_module,
00064:    &ngx_http_autoindex_module,
00065:    &ngx_http_index_module,
00066:    &ngx_http_auth_basic_module,
00067:    &ngx_http_access_module,
00068:    &ngx_http_limit_zone_module,
00069:    &ngx_http_limit_req_module,
00070:    &ngx_http_geo_module,
00071:    &ngx_http_map_module,
00072:    &ngx_http_split_clients_module,
00073:    &ngx_http_referer_module,
00074:    &ngx_http_rewrite_module,
00075:    &ngx_http_proxy_module,
00076:    &ngx_http_fastcgi_module,
00077:    &ngx_http_uwsgi_module,
00078:    &ngx_http_scgi_module,
00079:    &ngx_http_memcached_module,
00080:    &ngx_http_empty_gif_module,
00081:    &ngx_http_browser_module,
00082:    &ngx_http_upstream_ip_hash_module,
00083:    &ngx_http_stub_status_module,
00084:    &ngx_http_write_filter_module,
00085:    &ngx_http_header_filter_module,
00086:    &ngx_http_chunked_filter_module,
00087:    &ngx_http_range_header_filter_module,
00088:    &ngx_http_gzip_filter_module,
00089:    &ngx_http_postpone_filter_module,
00090:    &ngx_http_ssi_filter_module,
00091:    &ngx_http_charset_filter_module,
00092:    &ngx_http_userid_filter_module,
00093:    &ngx_http_headers_filter_module,
00094:    &ngx_http_copy_filter_module,
00095:    &ngx_http_range_body_filter_module,
00096:    &ngx_http_not_modified_filter_module,
00097:    NULL
00098: };
00099:

这里来分析nginx是如何初始化这些模块的:

(1)静态初始化(编译的时候的初始化):首先是调用NGX_MODULE_V1初始化前面7个不知道干什么用的域,接着用全局对象ngx_mname_module_ctx的地址来初始化ctx域,接着用全局数组ngx_mname_commands来初始化模块的commands域,然后用宏来初始化type字段,然后初始化init_master等回调函数,最后初始化最后8个不知道干嘛用的字段。


(2)动态初始化:在main函数中,会有如下的代码来初始化每个模块的index:

ngx_max_module = 0;
for (i = 0; ngx_modules[i]; i++) {
      ngx_modules[i]->index = ngx_max_module++;
}

然后对于ctx_index的初始化前面已经介绍过了。

本文的引用:

http://blog.csdn.net/livelylittlefish/article/details/6571497

http://blog.csdn.net/kenbinzhang/article/details/4663258

抱歉!评论已关闭.