Nginx模块开发系列1--预备知识

摘要:在进行Nginx模块开发之前,需要先了解一下Nginx的模块工作原理以及需要用到的结构体。

1、Nginx模块工作原理

当Nginx接到一个HTTP请求时,通过查找配置文件将此次请求映射到一个location块中,而此location中所配置的各个指令则会启动不同的模块去完成工作。通常一个location中的指令会涉及一个handler模块和多个filter模块(当然,多个location可以复用同一个模块)。handler模块负责处理请求,完成响应内容的生成,而filter模块对响应内容进行处理。
在这里插入图片描述
在Nginx模块开发中,最重要的三个结构体分别是:ngx_module_t、ngx_http_module_t 和 ngx_command_t。

ngx_module_t:构建nginx由多个ngx_module_t组成,该结构体描述了整个模块的所有信息,为核心模块进行初始化和调用提供了接口
ngx_http_module_t:实现ngx_module_t里面对应的功能
ngx_command_t:使用nginx模块的口令,可以有多个口令

ngx_module_t相当于房间,ngx_http_module_t相当于房间里是用来做什么的,ngx_command_t相当于多种钥匙

2、ngx_module_t 结构体

ngx_module_t 结构体是整个nginx的关键,它提供了整个nginx的模块化的基础,该结构体描述了整个模块的所有信息,为核心模块进行初始化和调用提供了接口。结构体定义及解释如下:

struct ngx_module_s {//相关空间初始化,赋值等可以参考ngx_http_block
    ...... // 其他参数,一般直接用 NGX_MODULE_V1 宏来填充
    void                 *ctx;      // 模块的上下文,例如http模块就用下面介绍的ngx_http_module_t 结构体定义
    ngx_command_t        *commands; // 下面将介绍的ngx_command_t结构体,用于nginx.conf相关的配置向参数解析
    ngx_uint_t            type;     // 模块类型
    ngx_int_t  (*init_master)(ngx_log_t *log);      // 实际没用,设为NULL
    ngx_int_t  (*init_module)(ngx_cycle_t *cycle);  // 指定初始化模块时调用的函数
    ngx_int_t  (*init_process)(ngx_cycle_t *cycle); // 指定初始化进程时调用的函数,ngx_worker_process_init或者ngx_single_process_cycle中调用
    ngx_int_t  (*init_thread)(ngx_cycle_t *cycle);  // 暂不支持多线程,实际没用,设为NULL
    void       (*exit_thread)(ngx_cycle_t *cycle);  // 暂不支持多线程,实际没用,设为NULL
    void       (*exit_process)(ngx_cycle_t *cycle); // 指定进程退出时调用的函数,ngx_single_process_cycle 或者 ngx_worker_process_exit中调用
    void       (*exit_master)(ngx_cycle_t *cycle);  // 指定master退出时调用的函数,ngx_master_process_exit中调用
    ...... // 其他参数, 一般用 NGX_MODULE_V1_PADDING 宏来填充
};

3、ngx_command_t 结构体

每个Nginx模块都会定义一个 commands 数组,用于定义和解析 nginx.conf 文件相关参数,每一个数组元素都是 ngx_command_t 类型,数组的结尾用 ngx_null_command 表示。Nginx在解析配置文件中的一个配置项时首先会遍历所有的模块,对于每一个模块而言,通过遍历commands数组进行。

struct ngx_command_s {  //所有配置的最初源头在ngx_init_cycle
    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: 当nginx.conf里出现了name这个字段就调用这个模块处理。
type: 告诉Nginx这个命令可以出现的位置,例如server或location
set: 配置项处理函数,将conf文件里的参数转化成需要的格式并存入配置结构体,可以自己实现,也可以用Nginx内置的14个配置解析函数(后面文章会介绍到)
conf:用于指示配置项所处内存的相对偏移位置,仅在type中没有设置NGX_DIRECT_CONF和NGX_MAIN_CONF时才会生效。HTTP模块中可能会定义3个结构体,分别用于存储main、srv、loc级别的配置项(对应于create_main_conf、create_srv_conf、create_loc_conf方法创建的结构体),而HTTP框架自动解析时需要知道应把解析出的配置项值写入哪个结构体中,这将由conf成员完成。
offset:当前配置项在整个存储配置项的结构体中的偏移位置,nginx内部使用 offsetof 计算成员变量在struct中的偏移位置得到。
post:功能由程序员定义

4、ngx_http_module_t

Nginx定义了很多模块,每个模块都有自己的类型,可以定义一些属于自己的操作函数,这里介绍http模块对应的结构体 ngx_http_module_t,结构体定义及解释如下:

typedef struct { //注意和ngx_http_conf_ctx_t结构配合
    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); // 常用于初始化main级别配置项
    void       *(*create_srv_conf)(ngx_conf_t *cf);   // 用于创建存储srv级别配置项的结构体
    char       *(*merge_srv_conf)(ngx_conf_t *cf, void *prev, void *conf); // 用于合并main级别和srv级别下的同名配置项
    void       *(*create_loc_conf)(ngx_conf_t *cf);   // 用于创建存储loc级别配置项的结构体
    char       *(*merge_loc_conf)(ngx_conf_t *cf, void *prev, void *conf); // 用于合并srv级别和loc级别下的同名配置项
} ngx_http_module_t;

5、零散知识

  • 5.1 ngx_chain_t 结构体
    在向用户发送HTTP 包体时,就要传入ngx_chain_t链表对象。ngx_chain_t 就是一个链表,用来存放完整的响应体,里面的ngx_buf_t 就是存放具体的响应体内容:
struct ngx_chain_s {
    ngx_buf_t    *buf;
    ngx_chain_t  *next;
};

其中ngx_buf_t里面改由pos和last变量,分别存放当前节点缓冲区在内存中的起始位置和结束位置,结构示意图如下所示:
在这里插入图片描述

  • 5.2 srv 和 loc
    在Nginx源码中,经常看到函数或宏定义出现srv、SRV、loc、LOC字样,这些分别是server和location的缩写,一般对应nginx.conf里的server段和location段。

下一节:Nginx模块开发系列2–hello_world框架

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值