其实经过前面文章的分析,我们已经知道在Nginx启动的时候会先进行core类型模块的处理。在Nginx的每一部分都会有一个core类型的模块与之对应,在解析配置文件的时候,这些core类型的模块便是这些他们所代表的部分的入口。例如event部分,ngx_events_module模块就是一个core类型的模块,因而我们可以看到event部分的初始化其实是从ngx_events_module模块的命令events的set回调函数开始的。
另外在每一部分都有一个比较重要的核心模块,例如event部分有ngx_event_core_module模块,其虽然只是一个event类型的模块,但是其却处理了event部分的大多数命令,而且它的配置结构也会保存很多十分重要的信息,例如ngx_event_core_module的配置结构ngx_event_conf_t就保存了event是否使用互斥信号,具体使用哪一个时间模块的等信息。其实要分析nginx每一部分就应该从这两个模块开始。
好了,那么就按照上面的说法来分析http部分吧,先找到core类型的模块,它是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
};
我们可以看到
ngx_http_module模块只有一个命令,那就是http,其的set回调函数式ngx_http_block函数。
(嗯,这个地方要插入一个话题,我们知道每种类型的模块的配置结构并不是保存在模块内部的,我们可以看到全局cycle变量有一个域是ctx,它用来保存“所有”模块的配置结构上下文,这里用引号是有道理的。其实ctx只是保存了每一部分core类型的模块的配置结构,然后再用core类型模块的配置结构来保存其所在部分的其余具体模块的配置结构,然后其余具体模块想要获取其的配置,就得先找到代表它的core类型的模块,进而才能找到其的配置结构。也就是说模块的配置结构的保存其实是按照层次来进行的,嗯,这个部分以后干脆写一篇文章来说明吧,这个比较关键,如果不搞透彻的话,对于理解代码会带来很大的问题。)
好了,说了太多的废话,接下来回归http。这里我们来看看http部分是如何来保存其具体模块的配置结构的吧。嗯,http部分还是比较奇葩的。这里要看一下ngx_http_conf_ctx_t这个结构:
//http模块的配置结构的定义
typedef struct {
void **main_conf; //所有http模块的main config数组(可以把它看成指针的数组)
void **srv_conf; //所有http模块的srv config数组
void **loc_conf; //所有http模块的 loc config数组
} ngx_http_conf_ctx_t;
在全局cycle变量的ctx域的
ngx_http_module模块index处将会保存这么一个结构,用它来索引其余所有http类型模块的配置结构。嗯,够奇葩的,也就是说每一个http模块最多有可能有三种配置结构了。
好了。接下开始http部分的核心模块了,它是ngx_http_core_module模块,我们先看一下它的定义:
static ngx_http_module_t ngx_http_core_module_ctx = {
ngx_http_core_preconfiguration, /* preconfiguration */
NULL, /* postconfiguration */
ngx_http_core_create_main_conf, /* create main configuration */
ngx_http_core_init_main_conf, /* init main configuration */
ngx_http_core_create_srv_conf, /* create server configuration */
ngx_http_core_merge_srv_conf, /* merge server configuration */
ngx_http_core_create_loc_conf, /* create location configuration */
ngx_http_core_merge_loc_conf /* merge location configuration */
};
ngx_module_t ngx_http_core_module = {
NGX_MODULE_V1,
&ngx_http_core_module_ctx, /* module context */
ngx_http_core_commands, /* module directives */
NGX_HTTP_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
};
由于其的命令太多了,这里就不贴出来了。只能说那些重要的命令都被这个模块包含了。然后我们在来看看它的配置结构吧,因为其配置结构将会保存http部分许多重要的配置信息。(这货居然三种类型的配置结构都有)我们首先来看它的main_conf(这个很重要):
typedef struct {
/**
* 存储所有的ngx_http_core_srv_conf_t,元素的个数等于server块的个数。
*/
ngx_array_t servers; /* ngx_http_core_srv_conf_t */
/**
* 包含所有phase,以及注册的phase handler,这些handler在处理http请求时,
* 会被依次调用,通过ngx_http_phase_handler_t的next字段串联起来组成一个
* 链表。
*/
ngx_http_phase_engine_t phase_engine;
/**
* 以hash存储的所有request header
*/
ngx_hash_t headers_in_hash;
/**
* 被索引的nginx变量 ,比如通过rewrite模块的set指令设置的变量,会在这个hash
* 中分配空间,而诸如$http_XXX和$cookie_XXX等内建变量不会在此分配空间。
*/
ngx_hash_t variables_hash;
/**
* ngx_http_variable_t类型的数组,所有被索引的nginx变量被存储在这个数组中。
* ngx_http_variable_t结构中有属性index,是该变量在这个数组的下标。
*/
ngx_array_t variables; /* ngx_http_variable_t */
ngx_uint_t ncaptures;
/**
* server names的hash表的允许的最大bucket数量,默认值是512。
*/
ngx_uint_t server_names_hash_max_size;
ngx_uint_t server_names_hash_bucket_size;
ngx_uint_t variables_hash_max_size;
ngx_uint_t variables_hash_bucket_size;
ngx_hash_keys_arrays_t *variables_keys;
/**
* 监听的所有端口,ngx_http_port_t类型,其中包含socket地址信息。
*/
ngx_array_t *ports;
ngx_uint_t try_files; /* unsigned try_files:1 */
/**
* 所有的phase的数组,其中每个元素是该phase上注册的handler的数组。
*/
ngx_http_phase_t phases[NGX_HTTP_LOG_PHASE + 1];
} ngx_http_core_main_conf_t;
这个配置结构一看就知道很重要了,首先来看servers域,它是一个
ngx_http_core_module模块的srv_conf结构的数组,听起来很奇葩,不过就是这样的,因为在http命令里面可能会包含几个server命令,知道这个也就不会觉得奇怪了,另外还有一个比较重要的域,那就是ports域,它代表所有需要监听的端口。
嗯,接下来看ngx_http_core_module模块的srv_conf类型的配置:
typedef struct {
/* array of the ngx_http_server_name_t, "server_name" directive */
ngx_array_t server_names; //server的名字数组
/* server ctx */
ngx_http_conf_ctx_t *ctx; // 指向包含它的ngx_http_conf_ctx_t结构
ngx_str_t server_name; //名字
size_t connection_pool_size;
size_t request_pool_size;
size_t client_header_buffer_size;
ngx_bufs_t large_client_header_buffers;
ngx_msec_t client_header_timeout;
ngx_flag_t ignore_invalid_headers;
ngx_flag_t merge_slashes;
ngx_flag_t underscores_in_headers;
unsigned listen:1; //区别当前server是否监听
#if (NGX_PCRE)
unsigned captures:1;
#endif
ngx_http_core_loc_conf_t **named_locations; //该srv配置的location配置数组
} ngx_http_core_srv_conf_t;
其实这个配置没什么好讲的,许多一看名字就能看的差不多知道什么意思了。接下就是
ngx_http_core_module模块的loc_conf了,嗯,这个结构是ngx_http_core_loc_conf_s,嗯,它的定义太长了,以后用到的时候再讲吧。
接下来我们来看一下http命令的一个例子吧,也就不难明白未什么要这么安排了:
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
#gzip on;
#反向代理配置 ,向内网6台jboss转发
upstream jboss {
server 192.168.162.35:8080 weight=10;
server 192.168.162.11:8080 weight=8;
server 192.168.162.61:8080 weight=2;
}
server {
listen 2011;
server_name localhost;
location ~ ^/nginx_status/ {
stub_status on;
access_log off;
}
location / {
proxy_pass http://jboss;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
}
一个http命令里面可能对应几个server命令,一个server命令又可能会对应好几个location命令。好吧,所以我们就知道一个http模块的配置信息可能存在三个地方,第一个就是http内,server外,这个用main_conf保存,还有一个是server内,location外,这个用srv_conf结构保存,还有的就是在location里面了,因而就用loc_conf配置结构来保存)
好了,已经写了这么多,居然还只是讲完了配置,嗯,那就下一篇在写真正的初始化过程吧。