http模块初始化过程

来源:互联网 发布:java 服务端mqtt推送 编辑:程序博客网 时间:2024/05/01 23:41

要理解一个核心部分,模块的初始化概括起来就是申请存储下一级模块配置结构体的空间,并且调用相应的回调生成模块的配置结构体,然后再开始通过ngx_conf_t指定的内容去解析配置文件,进行配置指令的存储
1.ngx_http_module_t
所有http模块都是ngx_http_module_t类型,所有的属性都是回调函数,在http模块初始化过程的不同阶段调用。当一个指令既允许出现在main块(在http{}块内,但是在server{}块外的区域)、server块(在server{}块内,但是在location{}块外的区域)、location块内时,就需要对这些指令进行继承和覆盖的处理,由merge_src_conf和merge_loc_conf完成。
[cpp] view plain copy print?
typedef struct {
/**
* 在解析配置文件中http{}配置块前调用
*/
ngx_int_t (*preconfiguration)(ngx_conf_t *cf);

/**  * 在解析配置文件中http{}配置块后调用  */  ngx_int_t   (*postconfiguration)(ngx_conf_t *cf);  /**  * 创建http模块的main config  */  void       *(*create_main_conf)(ngx_conf_t *cf);  /**  * 初始化http模块的main config  */  char       *(*init_main_conf)(ngx_conf_t *cf, void *conf);  /**  * 创建http模块的server config  */  void       *(*create_srv_conf)(ngx_conf_t *cf);  /**  * 合并http模块的server config,用于实现server config到main config的指令的继承、覆盖  */  char       *(*merge_srv_conf)(ngx_conf_t *cf, void *prev, void *conf);  /**  * 创建http模块的location config  */  void       *(*create_loc_conf)(ngx_conf_t *cf);  /**  * 合并http模块的location config,用于实现location config到server config的指令的继承、覆盖  */  char       *(*merge_loc_conf)(ngx_conf_t *cf, void *prev, void *conf);  

} ngx_http_module_t;
2.ngx_http_conf_ctx_t
此结构用于保存所有http模块的main、server和location的config结构。可以看到ngx_http_conf_ctx_t的三个属性就是三个数组,数组大小由ngx_http_max_module指定的,这个变量在指令http块的回调函数时初始化。即ngx_http_block(),而每一个模块的ctx_index属性就指示了模块的配置结构在三个数组里面的下标
nginx提供了俩类宏用来获取对应得配置块
1》#define ngx_http_conf_get_module_main_conf(r,module)
r是请求,module是具体的http模块
2》#define ngx_conf_get_module_main_conf(cf,moduole)
cf是ngx_conf_t类型,module是http模块
3.http模块的启动过程:
基本上是核心模块负责解析对应得模块,比如ngx_http_module负责解析http的其他模块
1》ngx_http_module结构:
static ngx_command_t ngx_http_commands[] = {

{ ngx_string("http"),    NGX_MAIN_CONF|NGX_CONF_BLOCK|NGX_CONF_NOARGS,    ngx_http_block,    0,    0,    NULL },    ngx_null_command  

};

static ngx_core_module_t ngx_http_module_ctx = {
ngx_string(“http”),
NULL,
NULL
};

ngx_module_t ngx_http_module = {
NGX_MODULE_V1,
&ngx_http_module_ctx, /* module context */
ngx_http_commands, /* module directives */
NGX_CORE_MODULE, /* module type */
NULL, /* init master */
NULL, /* init module */
NULL, /* init process */
NULL, /* init thread */
NULL, /* exit thread */
NULL, /* exit process */
NULL, /* exit master */
NGX_MODULE_V1_PADDING
};
可以看到它的type类型有ngx_conf_block,那么表示它是一个块指令,所以在解析所有核心模块的时候,如果遇到了http,那么就会调用ngx_http_block,来解析http模块的内容
2》ngx_http_block
先熟悉它的内部变量
ngx_uint_t mi, m, s;
ngx_conf_t pcf;
ngx_http_module_t *module;
ngx_http_conf_ctx_t *ctx;//存储三个指针的
ngx_http_core_loc_conf_t *clcf;
ngx_http_core_srv_conf_t **cscfp;
ngx_http_core_main_conf_t *cmcf;

/* the main http context */
ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_conf_ctx_t));
if (ctx == NULL) {
return NGX_CONF_ERROR;
}

/**
* 将传递进来的conf赋值为ctx,即ngx_http_conf_ctx_t类型。
* 这个conf是ngx_cycle->conf_ctx数组中的元素,而这个元素就是
* ngx_http_module模块对应的config信息。所以这一步就完成了
* ngx_http_module模块config信息的初始化。
*/
(ngx_http_conf_ctx_t *) conf = ctx;
是为了改变那个一级指针的内容,也就是刚好初始化了那个数组中的内容
ngx_http_max_module = 0;
for (m = 0; ngx_modules[m]; m++) {
if (ngx_modules[m]->type != NGX_HTTP_MODULE) {
continue;
}

ngx_modules[m]->ctx_index = ngx_http_max_module++;  

}
//更新每个模块的ctx_index属性
/* the http main_conf context, it is the same in the all http contexts */

ctx->main_conf = ngx_pcalloc(cf->pool,
sizeof(void ) ngx_http_max_module);
if (ctx->main_conf == NULL) {
return NGX_CONF_ERROR;
}

/*
* the http null srv_conf context, it is used to merge
* the server{}s’ srv_conf’s
*/

ctx->srv_conf = ngx_pcalloc(cf->pool, sizeof(void ) ngx_http_max_module);
if (ctx->srv_conf == NULL) {
return NGX_CONF_ERROR;
}

/*
* the http null loc_conf context, it is used to merge
* the server{}s’ loc_conf’s
*/

ctx->loc_conf = ngx_pcalloc(cf->pool, sizeof(void ) ngx_http_max_module);
if (ctx->loc_conf == NULL) {
return NGX_CONF_ERROR;
}
//接下来是根据ngx_http_max_module的大小给ctx的main,srv,loc分配空间
for (m = 0; ngx_modules[m]; m++) {
if (ngx_modules[m]->type != NGX_HTTP_MODULE) {
continue;
}

module = ngx_modules[m]->ctx;  mi = ngx_modules[m]->ctx_index;  if (module->create_main_conf) {      ctx->main_conf[mi] = module->create_main_conf(cf);      if (ctx->main_conf[mi] == NULL) {          return NGX_CONF_ERROR;      }  }  if (module->create_srv_conf) {      ctx->srv_conf[mi] = module->create_srv_conf(cf);      if (ctx->srv_conf[mi] == NULL) {          return NGX_CONF_ERROR;      }  }  if (module->create_loc_conf) {      ctx->loc_conf[mi] = module->create_loc_conf(cf);      if (ctx->loc_conf[mi] == NULL) {          return NGX_CONF_ERROR;      }  } 每个不同的模块通过create_main_conf等三个函数生成不同的结构体,比如ngx_http_core_module对应生成的是ngx_http_core_main_conf_t结构体,通过create_srv_conf生成的是ngx_http_core_srv_conf_t结构体,同时存入对应得main_conf数组,srv_conf数组中去。

/* 先保存cf的副本,待所有http module的指令解析完再恢复 */
pcf = *cf; //cf对应得是核心模块的结构,这会应该换成对应http模块的结构,因为要解析http模块了
/* 把解析http module的指令的上下文设置为ngx_http_conf_ctx_t */
cf->ctx = ctx;

/* 调用http module的preconfiguration回调函数 */
for (m = 0; ngx_modules[m]; m++) {
if (ngx_modules[m]->type != NGX_HTTP_MODULE) {
continue;
}

module = ngx_modules[m]->ctx;  if (module->preconfiguration) {      if (module->preconfiguration(cf) != NGX_OK) {          return NGX_CONF_ERROR;      }  }  

}

cf->module_type = NGX_HTTP_MODULE; // 只解析NGX_HTTP_MODULE模块的指令,即http module的指令
cf->cmd_type = NGX_HTTP_MAIN_CONF; // 只解析NGX_HTTP_MAIN_CONF类型的指令
/* 只有符合module_type和cmd_type的指令才会被解析 */
rv = ngx_conf_parse(cf, NULL)
有关该配置文件的具体解析过程,详细见配置文件的解析//
在ngx_conf_parse函数调用完成以后,所有的配置指令都已经解析完毕

接下来调用所有http module的init_main_conf回调函数初始化main config,ngx_http_merge_servers函数中会调用模块的merge_srv_conf和merge_loc_conf回调函数进行合并

for (s = 0; s < cmcf->servers.nelts; s++) {

clcf = cscfp[s]->ctx->loc_conf[ngx_http_core_module.ctx_index];  if (ngx_http_init_locations(cf, cscfp[s], clcf) != NGX_OK) {5      return NGX_CONF_ERROR;  }  if (ngx_http_init_static_location_trees(cf, clcf) != NGX_OK) {      return NGX_CONF_ERROR;  }  

}
//将location块组织成树状的结构

if (ngx_http_init_phases(cf, cmcf) != NGX_OK) {
return NGX_CONF_ERROR;
}
//nginx把请求的处理过程分为了11个阶段,除了某几个以外其他的都可以注册phase handler,在ngx_http_core_main_conf_t的结构体中的phases中保存了所以phase handler数组,这里完成每个phase的handler初始化(详细见phase handler初始化)
if (ngx_http_init_headers_in_hash(cf, cmcf) != NGX_OK) {
//把http请求的header初始化成hash结构,在ngx_http_headers_in数组中存储了所有的header,这里是根据该数组去初始化
调用所有http module的postconfiguration回调函数。
//调用配置文件解析完的postrconfiguration函数
ngx_http_init_phase_handlers(cf, cmcf) != NGX_OK)
//初始化phase handler,nginx把所有的phase handler存放在ngx_http_core_main_conf_t的phase_engine的handlers数组中,该结构是ngx_http_phase_handler_t类型的,它里面的一个next属性指示这该handlers数组的下标,那么处理请求的时候只需要遍历该数组就可以
(ngx_http_optimize_servers(cf, cmcf, cmcf->ports) != NGX_OK)
它完成ngx_http_conf_addr_t结构中的hash(server_name为key,ngx-http_core_srv_conf_t为值得hash结构),
最后调用ngx_http_init_listening函数,(具体过程详见监听socket初始化)

0 0
原创粉丝点击