第一点:ngx_command_t
ngx_core_commands是nginx中的核心模块指令, 它的类型就是ngx_command_t。在每一个module的结构体中,也都有一个ngx_command_t。
typedef struct ngx_command_s 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);
/* 当nginx在解析配置的时候,如果遇到这个配置指令,将会把读取到的值传递给这个函数进行解析保存。
因为具体每个配置指令的值如何处理,只有定义这个配置指令的人是最清楚的,set可能复杂也可能很简单。
比如errlog模块的“error_log”指令就是调用ngx_error_log写一条日志,并不需要存储什么配置数据。
* cf: 保存从配置文件读取到的原始字符串以及相关信息。这个参数的args字段是一个ngx_str_t类型的数组,
该数组首元素是这个配置指令本身,第二个元素开始才是参数。
cmd: 这个配置指令对应的ngx_command_t结构。
conf: 就是定义的存储这个配置值的结构体
*/
ngx_uint_t conf;
/* 该字段被NGX_HTTP_MODULE类型模块所用,指定当前配置项存储的内存位置。实际上是使用哪个内存池的问题。
因为http模块对所有http模块所要保存的配置信息,划分了main, server和location三个地方进行存储,
每个地方都有一个内存池用来分配存储这些信息的内存。
这里可能的值为NGX_HTTP_MAIN_CONF_OFFSET、NGX_HTTP_SRV_CONF_OFFSET或NGX_HTTP_LOC_CONF_OFFSET。
当然也可以直接置为0,就是NGX_HTTP_MAIN_CONF_OFFSET。
*/
ngx_uint_t offset;
/* 指定该配置项值的精确存放位置,一般指定为某一个结构体变量的字段偏移。
比如我们定义了一个结构体A,该项配置的值需要存储到该结构体的b字段。那么在这里就可以填写offsetof(A, b)。
对于有些配置项,它的值不需要保存或者是需要保存到更为复杂的结构中时,这里可以设置为0。
*/
void *post;
/* 可指向任何一个在读取配置过程中需要的数据,以便于进行配置读取的处理。大多时候不需要,设为0即可。*/
};
static ngx_command_t ngx_core_commands[]; // 保存了核心指令
第二点:ngx_module_t
对于开发一个模块来说,我们都需要定义一个ngx_module_t类型的变量来说明这个模块本身的信息,从某种意义上来说,这是这个模块最重要的一个信息。它告诉了nginx这个模块的一些信息,上面定义的配置信息,还有模块上下文信息,都是通过这个结构来告诉nginx系统的,也就是加载模块的上层代码,都需要通过定义的这个结构,来获取这些信息。
typedef struct ngx_module_s ngx_module_t;
struct ngx_module_s {
ngx_uint_t ctx_index;
/* 在相应模块类的计数,nginx模块分为四种:core、event、http和mail
* ctx->loc_conf[ngx_modules[i]->ctx_index] = mconf;
*/
ngx_uint_t index;
/* 模块计数器,按照每个模块在ngx_modules[]数组中的声明顺序,从0开始依次给每个模块赋值 */
ngx_uint_t spare0;
ngx_uint_t spare1;
ngx_uint_t spare2;
ngx_uint_t spare3;
ngx_uint_t version;
/* 模块当前版本 */
void *ctx;
/* 模块上下文,不同类别模块有不同上下文,ngx_http_conf_ctx_t/ngx_mail_conf_ctx_t/... */
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); // worker进程初始化调用
ngx_int_t (*init_thread)(ngx_cycle_t *cycle); // 线程初始化调用
void (*exit_thread)(ngx_cycle_t *cycle); // 线程退出调用
void (*exit_process)(ngx_cycle_t *cycle); // worker进程结束调用
void (*exit_master)(ngx_cycle_t *cycle); // master进程结束调用
/* callback:如果该模块需要发生这些行为执行特定的功能,可以通过这些回调函数指针注册一个回调函数接口来实现 */
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;
};
#define NGX_NUMBER_MAJOR 3
#define NGX_NUMBER_MINOR 1
#define NGX_MODULE_V1 0, 0, 0, 0, \
NGX_DSO_ABI_COMPATIBILITY, NGX_NUMBER_MAJOR, NGX_NUMBER_MINOR
/* 前7个成员初始化 */
#define NGX_MODULE_V1_PADDING 0, 0, 0, 0, 0, 0, 0, 0
/* 后8个成员初始化 */
第三点:ngx_conf_t
该结构体用于Nginx在解析配置文件时描述每个指令的属性,是Nginx程序中非常重要的一个数据结构。
typedef struct {
ngx_file_t file; // 文件
ngx_buf_t *buffer; // 文件内容
ngx_uint_t line; // 文件行数
} ngx_conf_file_t;
typedef char *(*ngx_conf_handler_pt)(ngx_conf_t *cf,
ngx_command_t *dummy, void *conf);
typedef struct ngx_conf_s ngx_conf_t
struct ngx_conf_s {
char *name; // 存放当前解析到的指令
ngx_array_t *args; // 从配置中读取指令的名称和相对应的参数
ngx_cycle_t *cycle; // 对应的cycle(一个进程有一个cycle)
ngx_pool_t *pool; // 对应的内存池
ngx_pool_t *temp_pool; // 临时内存池,在解析配置文件的时候使用,之后释放了
ngx_conf_file_t *conf_file; // 配置文件的信息
ngx_log_t *log; // 对应的log
void *ctx; // 上下文(指向模块配置信息)
ngx_uint_t module_type; // 处理当前指令的模块类型:core、event、mail和http
ngx_uint_t cmd_type; // 当前指令的类型
ngx_conf_handler_pt handler; // 自定义的指令处理函数
char *handler_conf; // 作为handler的参数,提供一些handler需要的配置信息
};
至此,基本的数据结构都看完了,开始学流程和机制吧!