Nginx 源码分析– 浅谈对模块module 的基本认知

分析nginx源码,谈到模块module是必然的。纵观nginx源码,可以说模块module机制是整个nginx的骨架。因此,对nginx的源码进行分析,那么对模块module就需要有一个基本的认知。在浅谈开始,我们要明确nginx模块构架是从编译阶段开始的,不像apache那样可以动态的添加模块,nginx使用的是静态模块。这应该也是nginx为何效率高的原因之一。对nginx的模块认知,必须要提到一篇大大有名的文章,我想也是每个分析nginx源码的人都拜读过的文章《Emiller’s Guide To Nginx Module Development 》里面的内容虽然少了点,但讲得非常经典,因此特别在这里推荐一个。

对模块module的认知,先来看三个数据结构。模块指令数据结构(ngx_command_t)、模块定义数据结构(ngx_module_t)、模块核心数据结构。模块核心数据结构具体来说可以分为4大类:

NGX_CORE_MODULE、NGX_CONF_MODULE、NGX_EVENT_MODULE和 NGX_HTTP_MODULE。对于这个数据结构本文选取其中的NGX_CORE_MODULE进行说明。

1、模块指令数据结构(ngx_command_t)

定义如下:

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;
};

name指代命令的类型,具体来说就是配置文件中的配置的参数名。type 为命令的类型如:在主配置文件中配置该命令参数为 NGX_HTTP_MAIN_CONF &#x3002;&#x53C2;&#x6570; <span>*(*set)(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) </span> &#x4E3A;&#x6267;&#x884C;&#x8BE5;&#x547D;&#x4EE4;&#x7684;&#x51FD;&#x6570;&#x3002;<span><span><span>conf&#xA0;</span></span></span> &#x4E3A;&#x914D;&#x7F6E;&#x4FE1;&#x606F;&#xFF0C;<span><span><span>offset</span></span></span> &#x504F;&#x79FB;&#x91CF;&#xFF0C;&#x6700;&#x540E;&#x4E00;&#x4E2A;&#x57FA;&#x672C;&#x4E0A;&#x90FD;&#x662F; <span>NULL</span> &#x3002;

<span>2</span> &#x3001;&#x6A21;&#x5757;&#x5B9A;&#x4E49;&#x6570;&#x636E;&#x7ED3;&#x6784;&#xFF08; <span>ngx_module_t</span> &#xFF09;

Nginx 源码分析-- 浅谈对模块module 的基本认知
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;
    ngx_command_t        *commands;
    ngx_uint_t            type;

    ngx_int_t           (*init_master)(ngx_log_t *log);

    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);

    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;
};

这个结构体参数比较多,但似乎其中的很多都没什么太大用。这里说明几个常用的参数基本认识一下, <span>index </span> &#x5728;&#x6240;&#x6709;&#x6A21;&#x5757;&#x4E2D;&#x7684;&#x4F4D;&#x7F6E;&#xFF0C;&#x53EF;&#x4EE5;&#x8BF4;&#x662F;&#x6E38;&#x6807;&#xFF0C;&#x56E0;&#x4E3A; <span>nginx</span> &#x6240;&#x6709;&#x7684;&#x6A21;&#x5757;&#x90FD;&#x653E;&#x5728;&#x4E86;&#x4E00;&#x4E2A;&#x6A21;&#x5757;&#x6570;&#x7EC4;&#x4E2D; <span>ngx_modules[]</span> &#x4E2D;&#xFF08;&#x8BE6;&#x60C5;&#x89C1;&#x540E;&#x6587;&#xFF09;&#x4E0D;&#x9700;&#x8981;&#x81EA;&#x5DF1;&#x8BBE;&#x7F6E;&#xFF0C;&#x81EA;&#x52A8;&#x751F;&#x6210;&#x7684;&#x3002; <span>*ctx </span> &#x6307;&#x5411;&#x6A21;&#x5757;&#x6838;&#x5FC3;&#x6570;&#x636E;&#x7ED3;&#x6784;&#x7684;&#x6307;&#x9488;&#xFF08;&#x6BCF;&#x4E2A;&#x6A21;&#x5757;&#x5FC5;&#x5907;&#xFF09;&#xFF0C; <span>*commands</span> &#x6307;&#x5411;&#x6A21;&#x5757;&#x6307;&#x4EE4;&#x6570;&#x636E;&#x7ED3;&#x6784;&#x7684;&#x6307;&#x9488;&#x3002; <span>type</span> &#x6A21;&#x5757;&#x7684;&#x7C7B;&#x578B;&#xFF0C;&#x63A5;&#x4E0B;&#x6765;&#x51E0;&#x4E2A;&#x51FD;&#x6570;&#x6307;&#x9488;&#x5C31;&#x662F;&#xFF0C;&#x5728;&#x67D0;&#x4E9B;&#x7279;&#x5B9A;&#x65F6;&#x5019;&#x9700;&#x8981;&#x8C03;&#x7528;&#x8BE5;&#x6A21;&#x5757;&#x5B8C;&#x6210;&#x4E9B;&#x529F;&#x80FD;&#xFF0C;&#x5982; <span>(*init_master)(ngx_log_t *log) </span> &#x5373;&#x5728; <span>master</span> &#x521D;&#x59CB;&#x5316;&#x65F6;&#x8C03;&#x7528;&#xFF0C;&#x5176;&#x4ED6;&#x7C7B;&#x662F;&#x3002;

<span>3</span> &#x3001;&#x6A21;&#x5757;&#x6838;&#x5FC3;&#x6570;&#x636E;&#x7ED3;&#x6784;

&#x3000;&#x3000;&#x524D;&#x9762;&#x5DF2;&#x7ECF;&#x8BF4;&#x660E;&#x4E86;&#xFF0C;&#x8FD9;&#x79CD;&#x6570;&#x636E;&#x7ED3;&#x6784;&#x6709; <span>4</span> &#x5927;&#x7C7B;&#xFF0C;&#x8FD9;&#x91CC;&#x9009;&#x53D6;&#xA0; <span>ngx_core_module_t&#xA0;</span>来进行简单认知。

typedef struct {

        ngx_str_t             name;  /*名字*/
        void               *(*create_conf)(ngx_cycle_t *cycle);  /*创建时调用*/
        char               *(*init_conf)(ngx_cycle_t *cycle, void *conf);    /*初始化时调用*/
    } ngx_core_module_t;

&#x3000;&#x8BA4;&#x8BC6;&#x5B8C;&#x4EE5;&#x4E0A;&#x4E09;&#x79CD;&#x6570;&#x636E;&#x7ED3;&#x6784;&#xFF0C;&#x90A3;&#x4E48;&#x6211;&#x4EEC;&#x5F00;&#x59CB;&#x597D;&#x5947;&#x8FD9;&#x4E09;&#x79CD;&#x6570;&#x636E;&#x7ED3;&#x6784;&#x662F;&#x600E;&#x6837;&#x5D4C;&#x5165;&#x5230;&#x6E90;&#x7801;&#x4E2D;&#x5DE5;&#x4F5C;&#x7684;&#x5462;&#xFF1F;&#x5982;&#x679C;&#x6709;&#x8BB0;&#x5F97;&#x7684;&#x5728;&#x524D;&#x6587;&#x4E2D;&#x63D0;&#x5230;&#x4E86; <span>ngx_modules[]</span> &#x8FD9;&#x6837;&#x7684;&#x4E00;&#x4E2A;&#x6570;&#x7EC4;&#xFF0C;&#x4F46;&#x662F;&#x5728;&#x6E90;&#x7801;&#x4E2D;&#x5374;&#x6CA1;&#x6709;&#xFF1F;&#x4E0D;&#x9519;&#xFF0C;&#x6E90;&#x7801;&#x4E2D;&#x786E;&#x5B9E;&#x6CA1;&#x6709;<span><span><span>ngx_modules[]</span></span></span> &#x8FD9;&#x6837;&#x7684;&#x4E00;&#x4E2A;&#x6570;&#x7EC4;&#xFF0C;&#x4F46;&#x8BF7;&#x4E0D;&#x8981;&#x5FD8;&#x4E86;<span><span><span>nginx</span></span></span> &#x7684;&#x8F6F;&#x4EF6;&#x6784;&#x5EFA;&#x662F;&#x4ECE;&#x7F16;&#x8BD1;&#x5F00;&#x59CB;&#x7684;&#x3002;&#x600E;&#x4E48;&#x7406;&#x89E3;&#xFF1F;&#x7B80;&#x5355;&#x7684;&#x7406;&#x89E3;&#xFF0C;&#x5C31;&#x662F;&#x90E8;&#x5206;&#x6E90;&#x7801;&#x7ED3;&#x6784;&#x4F53;&#x662F;&#x9700;&#x8981;&#x5728;<span><span><span>configure </span></span></span> &#x6267;&#x884C;&#x540E;&#x751F;&#x6210;&#x7684;&#x3002;&#x90A3;&#x4E48;&#x628A;&#x6A21;&#x5757;&#x5D4C;&#x5165;nginx&#x4E2D;&#x7684;&#x5DE5;&#x4F5C;&#x5C31;&#x4EA4;&#x7ED9;<span><span><span>configure</span></span></span> &#x5427;&#xFF01;&#x5728;&#x6267;&#x884C;&#x5B8C;<span><span><span>configure</span></span></span> &#x540E;&#xFF0C;&#x6253;&#x5F00;<span><span><span>objs</span></span></span> &#x6587;&#x4EF6;&#x5939;&#x770B;&#x5230;&#x4E00;&#x4E2A;<span><span><span>ngx_modules.c</span></span></span> &#x7684;&#x6587;&#x4EF6;&#xFF0C;&#x597D;&#x5947;&#x7684;&#xFF0C;&#x8D76;&#x7D27;&#x6253;&#x5F00;&#x770B;&#x770B;&#xFF0C;&#x91CC;&#x9762;&#x5C31;&#x6709;&#x4F60;&#x60F3;&#x77E5;&#x9053;&#x7684;&#x5185;&#x5BB9;&#xFF01;

<span>ngx_module_t *ngx_modules[] = { </span>
<span>&ngx_core_module, </span>
<span>&ngx_errlog_module, </span>

&#x2026;

<span>}</span>

&#x3000;&#x660E;&#x767D;&#x4E86;&#x5427;&#xFF01;&#x6A21;&#x5757;&#x7684;&#x7F16;&#x8BD1;&#x540E;&#x7684;&#x5730;&#x5740;&#x90FD;&#x5728;&#x8FD9;&#x91CC;&#xFF0C;&#x662F;&#x4E0D;&#x662F;&#x611F;&#x6168; <span><span><span>nginx</span></span></span> &#x7CBE;&#x5999;&#x7684;&#x6784;&#x5EFA;&#xFF01;&#x8BF4;&#x5230;&#x8FD9;&#x91CC;&#xFF0C;&#x4F60;&#x53EF;&#x80FD;&#x8FD8;&#x662F;&#x4F3C;&#x61C2;&#x975E;&#x61C2;&#xFF0C;&#x90A3;&#x4E48;&#x6211;&#x81EA;&#x5DF1;&#x6765;&#x5199;&#x4E00;&#x4E2A;&#x6A21;&#x5757; <span>module </span> &#x6765;&#x5BF9;&#x4ECB;&#x7ECD;&#x7684;&#x57FA;&#x672C;&#x8BA4;&#x77E5;&#x8FDB;&#x884C;&#x7406;&#x6027;&#x7684;&#x770B;&#x5F85;,&#x4E5F;&#x52A0;&#x6DF1;&#x5BF9;&#x524D;&#x9762;&#x6240;&#x8BF4;&#x7684;&#x7406;&#x89E3;&#xFF0C;&#x5B66;&#x4EE5;&#x81F4;&#x7528;&#xFF01;&#x8FD9;&#x91CC;&#x5199;&#x7684;&#x662F; <span>ngx_core_module_t </span> <span><span>&#x7C7B;&#x578B;&#x6A21;&#x5757;&#xFF0C;&#x6838;&#x5FC3;&#x6A21;&#x5757;&#x3002;&#x4E3A;&#x4E86;&#x7A81;&#x51FA;&#x4E3B;&#x5E72;&#xFF0C;&#x5E76;&#x6CA1;&#x6709;&#x5199;&#x4EC0;&#x4E48;&#x529F;&#x80FD;&#x4EC5;&#x6F14;&#x793A;&#x4E0B;&#x800C;&#x5DF2;&#x3002;&#x9996;&#x5148;&#xFF0C;&#x5728;src&#x6587;&#x4EF6;&#x5939;&#x4E0B;&#x5EFA;&#x7ACB;test&#x6587;&#x4EF6;&#x5939;&#xFF0C;&#x540E;&#x6DFB;&#x52A0;test.c&#x6E90;&#x6587;&#x4EF6;&#xFF0C;&#x4EE3;&#x7801;&#x5982;&#x4E0B;</span>&#xFF1A;</span>

#include
#include

static void *ngx_test_module_create_conf(ngx_cycle_t *cycle);
char * ngx_test(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);

static ngx_command_t ngx_test_commands[] = {
     {
     ngx_string("commands"),
         NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_NOARGS,/*第一参数,模块中没有初始化函数;第二参数,nginx.conf配置文件的指令配置类型,就像worker_processes;第三个参数,该指令后面没有参数*/
         ngx_test,
         0,
         0,
         NULL
      },
      ngx_null_command /*命令集结束*/
};

static ngx_core_module_t ngx_test_module_ctx = {
    ngx_string("test"),
    ngx_test_module_create_conf,
    NULL
};

ngx_module_t ngx_test_module = {
    NGX_MODULE_V1,
    &ngx_test_module_ctx,
    ngx_test_commands,
    NGX_CORE_MODULE,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NGX_MODULE_V1_PADDING
};

char * ngx_test(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
    FILE *fp = fopen("test", "w");
    fprintf(fp,"call ngx_test\n");
    fclose(fp);
    return NGX_CONF_OK;

}

static void *ngx_test_module_create_conf(ngx_cycle_t *cycle){
    printf("call ngx_test_module_create_conf\n");
}

对代码进行简单说明下,三大结构体前文已经说了,代码功能为:显示模块创建是调用了ngx_test_module_create_conf,若配置文件中有 commands 指令就会在nginx所在目录下创建test文件,并向其中写入call ngx_test这个字符串。

建立 config 文件,主要用于configure时将我们写的test模块包括进去。内容如下:

ngx_addon_name=ngx_test_module
CORE_MODULES="$CORE_MODULES ngx_test_module"
NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/test.c"

三条语句,三个功能:指定添加模块名,指定模块类型,指定模块源文件路径

然后,我们执行configure 注意添加参数,加入我们编写的test模块:

./configure –add-module=src/test

执行过程中,可以发现

configuring additional modules
adding module in src/test
+ ngx_test_module was configured

这条信息即可表示我们编写的test模块已经添加进编译过程了。如果比较好奇,nginx中有多少默认(直接configure不添加其他参数)的核心模块,我们不妨找到源码中的 ngx_cycle.c (本人用的是 nginx 1.3.0版本代码)文件,将其中添加上一条printf语句,详细如下:

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

        module = ngx_modules[i]->ctx;
        printf("core modules:  %s \n",module->name.data);
        if (module->create_conf) {
            rv = module->create_conf(cycle);
            if (rv == NULL) {
                ngx_destroy_pool(pool);
                return NULL;
            }
            cycle->conf_ctx[ngx_modules[i]->index] = rv;
        }
    }

好了,工作基本完成了,make一下,然后sudo make install。 哦,对了,别忘记了在nginx.conf 中 加上 ” commands; “,要不然我们写的ngx_command_t 不会执行了。运行nginx后,运行结果如下:

Nginx 源码分析-- 浅谈对模块module 的基本认知

Nginx 源码分析-- 浅谈对模块module 的基本认知

Nginx 源码分析-- 浅谈对模块module 的基本认知

图1 自定义nginx核心模块运行结果

阅读到这里,我想大家应该对nginx 中的 module 有了一个基本的认知,要想了解nginx的运行机制这点应该很重要的。如果要对源码进行分析,本文提到的几个结构体就应该更加要熟悉了。nginx 中的功能都是以模块的形式进行开发的,如events、http等,就是日志系统(errlog)也是用模块实现,即使并不想分析源码有了这些基本的认知对于理解配置nginx也应有很大的帮助!

Original: https://www.cnblogs.com/jzhlin/archive/2012/06/09/module.html
Author: Java研究者
Title: Nginx 源码分析– 浅谈对模块module 的基本认知

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/616204/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球