• 解剖Nginx·模块开发篇(2)ngx_http_hello_world_module 模块基本结构定义


    elloWorld 是一个典型的 location 模块。什么是 location 模块?在 Nginx 中,根据作用域,有 main 模块、server 模块、location 模块。

    1 模块定义

    在 HelloWorld 模块中有一个 ngx_http_hello_world_module 变量,用于定义模块。它是 ngx_module_t 类型。ngx_module_t 是 ngx_module_s 的别名,其定义如下:

    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; // Nginx模块版本
    
        void                 *ctx; // 上下文定义的地址
        ngx_command_t        *commands; // 命令定义地址
        ngx_uint_t            type; // 模块类型
    
        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;
    };
    

    在 HelloWorld 例子中:

    // Structure for the HelloWorld module, the most important thing
    ngx_module_t ngx_http_hello_world_module = {
        NGX_MODULE_V1,
        &ngx_http_hello_world_module_ctx,
        ngx_http_hello_world_commands,
        NGX_HTTP_MODULE,
        NULL,
        NULL,
        NULL,
        NULL,
        NULL,
        NULL,
        NULL,
        NGX_MODULE_V1_PADDING
    };
    

    1.1 NGX_MODULE_V1

    看它的定义你就知道,它是用来填充前 7 个 fields 的。

    NGX_MODULE_V1          0, 0, 0, 0, 0, 0, 1
    

    1.2 模块类型

    我们的模块是 HTTP 模块,还可以开发 CORE 模块,或者 CONF 模块等等。

    // ngx_http_config.h
    #define NGX_HTTP_MODULE      0x50545448   /* "HTTP" */
    
    // ngx_conf_file.h
    #define NGX_CORE_MODULE      0x45524F43  /* "CORE" */
    #define NGX_CONF_MODULE      0x464E4F43  /* "CONF" */
    

    1.3 NGX_MODULE_V1_PADDING

    这个还是用来填充字段的,或者叫 padding、补白。

    #define NGX_MODULE_V1_PADDING  0, 0, 0, 0, 0, 0, 0, 0
    

    2 命令定义

    命令定义用到如下数据结构:

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

    一般类说会定义很多命令,但是在 HelloWorld 中只有一个命令。

    static ngx_command_t ngx_http_hello_world_commands[] = {
        {
            ngx_string("hello_world"), // The command name
            NGX_HTTP_LOC_CONF | NGX_CONF_TAKE1,
            ngx_http_hello_world, // The command handler
            NGX_HTTP_LOC_CONF_OFFSET,
            offsetof(ngx_http_hello_world_loc_conf_t, output_words),
            NULL
        },
        ngx_null_command
    };
    

    我们一个一个来看。

    2.1 命令名称

    name 成员表示命令名称

    2.2 命令类型

    type 是命令类型。它可以取如下的一个或多个值的“或”:

    • NGX_HTTP_MAIN_CONF:可出现在 http 的主作用域;
    • NGX_HTTP_SRV_CONF:可出现在 http 的 server 作用域;
    • NGX_HTTP_LOC_CONF:可出现在 http 的 location 作用域;
    • NGX_HTTP_UPS_CONF:可出现在 http 的 upstream 作用域;
    • NGX_HTTP_SIF_CONF:which will allow the directive to be included in if statements at the server level. [参考]
    • NGX_CONF_NOARGS:指令没有参数;
    • NGX_CONF_TAKE1:指令读入1个参数;
    • NGX_CONF_TAKE2:指令读入2个参数;
    • NGX_CONF_TAKE7:指令读入7个参数;
    • NGX_CONF_FLAG:指令读入1个布尔型数据(“on”或“off”);
    • NGX_CONF_1MORE:指令至少读入1个参数;
    • NGX_CONF_2MORE:指令至少读入2个参数;

        // ngx_http_config.h
        #define NGX_HTTP_MAIN_CONF        0x02000000
        #define NGX_HTTP_SRV_CONF         0x04000000
        #define NGX_HTTP_LOC_CONF         0x08000000
        #define NGX_HTTP_UPS_CONF         0x10000000
        #define NGX_HTTP_SIF_CONF         0x20000000
        #define NGX_HTTP_LIF_CONF         0x40000000
        #define NGX_HTTP_LMT_CONF         0x80000000
      
        // ngx_conf_file.h
        #define NGX_CONF_NOARGS      0x00000001
        #define NGX_CONF_TAKE1       0x00000002
        #define NGX_CONF_TAKE2       0x00000004
        #define NGX_CONF_TAKE3       0x00000008
        #define NGX_CONF_TAKE4       0x00000010
        #define NGX_CONF_TAKE5       0x00000020
        #define NGX_CONF_TAKE6       0x00000040
        #define NGX_CONF_TAKE7       0x00000080
      
        // ngx_conf_file.h      
        #define NGX_CONF_TAKE12      (NGX_CONF_TAKE1|NGX_CONF_TAKE2)
        #define NGX_CONF_TAKE13      (NGX_CONF_TAKE1|NGX_CONF_TAKE3)
        #define NGX_CONF_TAKE23      (NGX_CONF_TAKE2|NGX_CONF_TAKE3)
        #define NGX_CONF_TAKE123     (NGX_CONF_TAKE1|NGX_CONF_TAKE2|NGX_CONF_TAKE3)
        #define NGX_CONF_TAKE1234    (NGX_CONF_TAKE1|NGX_CONF_TAKE2|NGX_CONF_TAKE3|NGX_CONF_TAKE4)
      
        // ngx_conf_file.h
        #define NGX_CONF_ARGS_NUMBER 0x000000ff
        #define NGX_CONF_BLOCK       0x00000100
        #define NGX_CONF_FLAG        0x00000200
        #define NGX_CONF_ANY         0x00000400
        #define NGX_CONF_1MORE       0x00000800
        #define NGX_CONF_2MORE       0x00001000
        #define NGX_CONF_MULTI       0x00002000
      

    2.3 命令回调函数

    这里我们使用的是自己定义的回调函数,还可以使用 Nginx 提供的回调函数,比如:

    • ngx_conf_set_flag_slot:将“on”或者“off”转换成1或0;
    • ngx_conf_set_str_slot:将字符串保存为ngx_str_t;
    • ngx_conf_set_num_slot:解析一个数字并保存为ngx_int_t;
    • ngx_conf_set_size_slot:解析一个数据大小(如:“8k”,“1m”),并保存为size_t;
    • ngx_conf_set_enum_slot:根据枚举定义将字符串翻译成ngx_int_t;
    • ngx_http_set_complex_value_slot:解析一个包含nginx变量的字符串并保存为ngx_http_complex_value_t;

    2.4 存储位置

    conf 参数它有三个可能的取值,分别如下:

    NGX_HTTP_MAIN_CONF_OFFSET
    NGX_HTTP_SRV_CONF_OFFSET
    NGX_HTTP_LOC_CONF_OFFSET
    

    这可不是随意指定的,如果你的type参数设置了NGX_HTTP_MAIN_CONF,那么这里就要设置为NGX_HTTP_MAIN_CONF_OFFSET。相应的,如果是NGX_HTTP_SRV_CONFNGX_HTTP_LOC_CONF,那么这里就要设置为NGX_HTTP_SRV_CONF_OFFSETNGX_HTTP_LOC_CONF_OFFSET

    2.5 offset

    表 示数据具体保存在main_conf、srv_conf、loc_conf指向的结构体的哪个位置(offset偏移)。大家可能会问,这个 main_conf等等怎么来的,nginx给我们挖的坑长得是个什么样子,这个我们在介绍 ngx_http_hello_world_module_ctx会说到。

    2.6 post

    一个补充字段,一般不用的,填入NULL。只是对于某些特殊的处理函数,比如ngx_conf_set_enum_slot,会用这个指针来指向enum定义表。

    最后不要忘了加上 ngx_null_command,以表示命令集合定义完成。

    3 上下文定义

    用到了 HTTP 模块,定义如下:

    typedef struct {
        ngx_int_t   (*preconfiguration)(ngx_conf_t *cf); 
        ngx_int_t   (*postconfiguration)(ngx_conf_t *cf);
    
        void       *(*create_main_conf)(ngx_conf_t *cf);
        char       *(*init_main_conf)(ngx_conf_t *cf, void *conf);
    
        void       *(*create_srv_conf)(ngx_conf_t *cf);
        char       *(*merge_srv_conf)(ngx_conf_t *cf, void *prev, void *conf);
    
        void       *(*create_loc_conf)(ngx_conf_t *cf);
        char       *(*merge_loc_conf)(ngx_conf_t *cf, void *prev, void *conf);
    } ngx_http_module_t;
    

    可看到有以下几个部分:

    • Pre configuration
    • Post configuration
    • create main configuration
    • init main configuration
    • create server configuration
    • merge server configuration
    • create location configuration
    • merge location configuration

    它们都是函数指针,都可以为 NULL,不过我们的模块里用到的是:

    // Structure for the HelloWorld context
    static ngx_http_module_t ngx_http_hello_world_module_ctx = {
        NULL,
        NULL,
        NULL,
        NULL,
        NULL,
        NULL,
        ngx_http_hello_world_create_loc_conf,
        ngx_http_hello_world_merge_loc_conf
    };
    

    这两个函数会在下一篇文章中介绍。

    4 Reference

    1. http://forum.nginx.org/read.php?2,243
    2. http://blog.sina.com.cn/s/blog_7303a1dc0100x70t.html

    -

  • 相关阅读:
    在linux上开发210的hdmi-servers输出
    haproxy.cfg
    【Quartz】Quartz的搭建、应用(单独使用Quartz)
    application.xml定时
    URLEncode转json
    Callable与Future的简单介绍
    Java并发:Callable、Future和FutureTask
    Java并发编程:Callable、Future和FutureTask
    EXECUTORSERVICE线程池讲解
    ExecutorService中submit和execute的区别
  • 原文地址:https://www.cnblogs.com/breg/p/4043642.html
Copyright © 2020-2023  润新知