Nginx学习之路(十)编写一个Nginx的模块-----基本的模块编写步骤

在Nginx上做二次开发大部分时候都是做的模块(module)的开发,今天就来介绍一下Nginx中的module开发的基本步骤,先来认识一下Nginx中的module。

一个基本的module框架(叫框架可能不太准确,这里的意思是需要编写的地方)由以下3个部分组成:

首先是必须要实现的一个command结构体

struct ngx_command_s {    
    ngx_str_t             name;//这个name就是你在需要使用这个module时,在conf文件配置指令的名称    
    ngx_uint_t            type;//type可以是一串指令的并集,它的功能是用来指定这个module应该出现在配置文件中的哪个地方,以及这个配置指令接受几个参数等    
    char              *(*set)(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);//这个回调函数的功能是当conf文件开始解析这个配置指令时,就会调用这个回调    
    ngx_uint_t conf;//conf字段指定该配置项存储的位置到底在哪个内存池下面,有三个选项NGX_HTTP_MAIN_CONF_OFFSET,NGX_HTTP_SRV_CONF_OFFSET,NGX_HTTP_LOC_CONF_OFFSET    
    ngx_uint_t offset;//offset一般会调用一个offsetof()函数,用于指定配置的指令数据的存放位置距离conf指针偏移值具体为多少   
    void *post;//该字段存储一个指针。可以指向任何一个在读取配置过程中需要的数据,以便于进行配置读取的处理。大多数时候,都不需要,所以简单地设为0即可    
};  

然后需要实现这个module的上下文,上下文的概念可能有点抽象,在这里可以理解成就是注册这个module在Nginx运行的各个阶段需要被调用的相应函数就可以了,上下文的结构体如下:

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);//调用该函数创建本模块位于http block的配置信息存储结构。该函数成功的时候,返回创建的配置对象。失败的话,返回NULL。
    char       *(*init_main_conf)(ngx_conf_t *cf, void *conf);//调用该函数初始化本模块位于http block的配置信息存储结构。该函数成功的时候,返回NGX_CONF_OK。失败的话,返回NGX_CONF_ERROR或错误字符串。

    void       *(*create_srv_conf)(ngx_conf_t *cf);//调用该函数创建本模块位于http server block的配置信息存储结构,每个server block会创建一个。该函数成功的时候,返回创建的配置对象。失败的话,返回NULL。
    char       *(*merge_srv_conf)(ngx_conf_t *cf, void *prev, void *conf);//因为有些配置指令既可以出现在http block,也可以出现在http server block中。那么遇到这种情况,每个server都会有自己存储结构来存储该server的配置,但是在这种情况下http block中的配置与server block中的配置信息发生冲突的时候,就需要调用此函数进行合并,该函数并非必须提供,当预计到绝对不会发生需要合并的情况的时候,就无需提供。当然为了安全起见还是建议提供。该函数执行成功的时候,返回NGX_CONF_OK。失败的话,返回NGX_CONF_ERROR或错误字符串。

    void       *(*create_loc_conf)(ngx_conf_t *cf);//调用该函数创建本模块位于location block的配置信息存储结构。每个在配置中指明的location创建一个。该函数执行成功,返回创建的配置对象。失败的话,返回NULL。
    char       *(*merge_loc_conf)(ngx_conf_t *cf, void *prev, void *conf);//与merge_srv_conf类似,这个也是进行配置值合并的地方。该函数成功的时候,返回NGX_CONF_OK。失败的话,返回NGX_CONF_ERROR或错误字符串。
} ngx_http_module_t;

这两个部分写好后就是最关键的部分了,需要实现一个module声明的结构体,该结构体如下:

typedef struct ngx_module_s      ngx_module_t;
struct ngx_module_s {
    ngx_uint_t            ctx_index;//后面会根据这个ctx_index来调用前面create_.._conf创建的上下文
    ngx_uint_t            index;
    ngx_uint_t            spare0;
    ngx_uint_t            spare1;
    ngx_uint_t            abi_compatibility;
    ngx_uint_t            major_version;
    ngx_uint_t            minor_version;
    void                 *ctx;
    ngx_command_t        *commands;
    ngx_uint_t            type;
    ngx_int_t           (*init_master)(ngx_log_t *log);//init 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);
    uintptr_t             spare_hook0;//提供一些hook点
    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;
};

以上三个基本块完成后,需要完成一个config文件,这个config文件的作用是当你添加这个模块到configure中时,在configure阶段就会扫描这个config文件,然后读取里面的一些配置命令,如auto . have,auto .feature等等,下面简单说下auto have和auto feature

auto have一般用于作为一个开关的配置命令,使用auto have 就会在代码中define一个你编写的变量

auto feature一般用于环境检查,auto feature会将你编写的一段代码添加到模块代码中,然后编译,如果能通过则会返回一个yes。

一个简单的config文件就如下

ngx_addon_name=ngx_http_hello_module 
HTTP_MODULES="$HTTP_MODULES ngx_http_hello_module"
NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/ngx_http_hello_module.c"//如果这个模块的实现有多个源文件,那么都在NGX_ADDON_SRCS这个变量里



评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值