學習Nginx若是直接看代碼那確定會瘋掉的,幸虧有許多前輩的文章和書籍參考,和在某高人指點下,我開始從一個簡單的HTTP模塊入手,開始個人學習之旅。nginx
網上有不少Nginx的Helloworld模塊編寫教程,我也是參考了其中一個,先實現了一遍,這裏貼一下我看的教程http://blog.csdn.net/poechant/article/details/7627828,實現以後我也有諸多疑問(徹底搞不懂在幹什麼,反正是實現了...),如今就結合他寫的代碼和我最近的學習成果,分析一下這些代碼究竟幹了什麼,和Nginx是怎麼聯繫起來的。數據結構
首先,要寫http模塊就得先取個名字,教程中的模塊名稱爲ngx_http_hello_world_module,與此相對應的數據結構是框架
ngx_module_t ngx_http_hello_world_module = { NGX_MODULE_V1, &ngx_http_hello_world_module_ctx, ngx_http_hello_world_commands, NGX_HTTP_MODULE, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NGX_MODULE_V1_PADDING };
先看一下ngx_module_t的定義函數
typedef struct ngx_module_s ngx_module_t struct ngx_module_s { ngx_uint_t ctx_index; ngx_uint_t index; ngx_uint_t spare0; ngx_uint_t spare1; ngx_uint_t spare2; ngx_uint_t spare3; ngx_uint_t version; void *ctx; ngx_command_t *commands; ngx_uint_t type; ngx_int_t (*init_master)(ngx_log_t *log); 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; 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; };
能夠看到ngx_http_hello_world_module中先對經過NGX_MODULE_V1宏對前7個參數作了初始化post
#NGX_MODULE_V1 0,0,0,0,0,0,1
接着將*ctx和*commands分別指向另外定義的2個數據結構,將type定義爲NGX_HTTP_MODULE,以後將7個回調函數賦值爲NULL,再用NGX_MODULE_V1_PADDING宏對最後8各參數作了初始化學習
#NGX_MODULE_V1_PADDING 0,0,0,0,0,0,0,0
這裏咱們須要關心的是*ctx和*commands這2個指針和其對應的數據結構ui
*ctx:用於指向模塊的上下文結構體,因爲Nginx中不一樣模塊的功能都各不相同,因此設計爲void*類型,在HTTP模塊中須要指向ngx_http_module_t結構體。spa
*commands:用於處理nginx.conf中的配置項。.net
PS:看到這裏能夠發現,只要Nginx可以訪問到ngx_http_hello_world_module,就能訪問到另外2個數據結構了。設計
如今來看*ctx指向的ngx_http_hello_world_module_ctx
static ngx_http_module_t ngx_http_hello_world_module_ctx = { NULL, NULL, NULL, NULL, NULL, NULL, ngx_http_hello_world_create_loc_conf, ngx_http_hello_world_merge_loc_conf };
ngx_http_module_t的定義
typedef struct ngx_http_module_s ngx_http_module_t struct ngx_http_module_s{ 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); void *(*create_srv_conf)(ngx_conf_t *cf); char *(*merge_srv_conf)(ngx_conf_t *cf, void *prev, void *conf); void *(*create_loc_conf)(ngx_conf_t *cf); char *(*merge_loc_conf)(ngx_conf_t *cf, void *prev, void *conf); } ;
ngx_http_hello_world_module_ctx中只指向了咱們定義的2個函數,其中ngx_http_hello_world_create_loc_conf用於建立存儲配置項的數據結構,並將該結構的地址返回給Nginx框架,在這個函數中建立了咱們爲模塊自定義的數據結構,
typedef struct { ngx_str_t output_words; } ngx_http_hello_world_loc_conf_t;
而ngx_http_hello_world_merge_loc_conf用於合併srv和loc級別下的同名配置項(意思就是不一樣級別的配置項中出現了名字相同的配置項以哪一個爲準,具體標準由模塊實現者決定)。這個結構中的函數在NginxHTTP框架啓動過程當中自動調用。
接着來看*commands指向的ngx_http_hello_world_commands
static ngx_command_t ngx_http_hello_world_commands[] = { { ngx_string("hello_world"), // The command name NGX_HTTP_LOC_CONF | NGX_CONF_TAKE1, ngx_http_hello_world, // The command handler NGX_HTTP_LOC_CONF_OFFSET, offsetof(ngx_http_hello_world_loc_conf_t, output_words), NULL }, ngx_null_command };
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); ngx_uint_t conf; ngx_uint_t offset; void *post; };
name:指定了咱們感興趣的配置項的名稱,其中ngx_string是一個宏,用於將字符串轉換爲ngx_str_t類型數據。
type:表示配置項能夠出現的位置和接受參數的個數,set方法用於處理配置項的參數。
conf:用於表示用何級別的方法生成的結構體來保存這個參數。
offset:表示這個配置項在所對應的參數再結構中的偏移位置(offsetof能夠直接給出結構體中數據項的位置)。
*post:這個用途就有不少了,這裏就不討論了。
看到這裏能夠發現只要nginx.conf文件中出現了hello_world配置項就會調用ngx_http_hello_world對配置項進行處理。
咱們發現咱們定義的ngx_http_hello_world_commands的結構中有2個ngx_command_t結構(ngx_null_command爲一個宏,定義一個空的ngx_command_t),這是由於咱們的配置項可能有不少,ngx_null_command表示再也不須要解析配置項了(個人理解)。
這裏咱們已經將該模塊的幾個主要的數據結構分析了一遍,可能還不夠深入,有空再把文中提到的數據結構詳細整理一遍。