src\core\ngx_conf_file.h src\core\ngx_conf_file.c
本篇的主要目的在於分析Nginx
的配置功能。因爲Nginx
的配置基本就是對模塊的配置,所以,在討論配置功能以前,須要先分析Nginx
的模塊功能。nginx
對於模塊功能,這裏的重點不在於某個模塊的細節,而在於分析Nginx
的模塊架構是如何設計的。web
相似地,由於對於Nginx
的配置文件,沒有資料比官方文檔上說得更明白,因此,這裏的重點並非對配置文件,而是分析Nginx
的配置功能是如何設計的。數組
好了,開始吧。服務器
Nginx
的基礎架構是高度模塊化的。能夠從多個方面來觀察Nginx
的模塊化。架構
官方文檔首頁的整個下半頁是Nginx
自身全部模塊的列表。從這裏能夠看到Nginx
的模塊輪廓。框架
若是從源碼安裝Nginx
,那麼首先執行的configure
腳本的配置參數裏,很大一部分是用來管理是否安裝某個模塊的。固然,Nginx
運行必備的模塊是必須安裝的,所以,並不會出如今configure
的配置選項裏。模塊化
Nginx
自己由多個基本的模塊構成,其中,核心的部分是一個叫ngx_core_module
的模塊。固然,對於一個web服務器,僅僅有一個核心是不夠的,還須要大量的「輔助模塊」。這有點像Linux
的設計,一堆外圍設施做爲模塊與Linux
內核構成整個Linux
系統。函數
很天然的會想到,Nginx
的這種模塊化設計是支持第三方插件的。這種設計也大大增長了Nginx
的彈性和能力。post
既然Nginx
是由許多模塊構成的,那麼,如何組織和管理這些模塊是首先要關注的問題。在Nginx
中,使用全局數組ngx_modules
保存和管理全部Nginx
的模塊。ui
如何作到的呢?
首先,Nginx
的衆多模塊被分紅兩類:必須安裝的模塊和能夠安裝的模塊。
ngx_modules
裏。好比ngx_core_module
configure
的配置和系統環境,被有選擇的安裝,這些模塊裏,被選擇安裝的模塊會出如今ngx_modules
數組中。當configure
執行結束後,會生成一個objs\ngx_modules.c
的源代碼文件:
文件內容隨configure
配置不一樣而不一樣,例如:
#include <ngx_config.h> #include <ngx_core.h> extern ngx_module_t ngx_core_module; extern ngx_module_t ngx_errlog_module; extern ngx_module_t ngx_conf_module; extern ngx_module_t ngx_events_module; extern ngx_module_t ngx_event_core_module; extern ngx_module_t ngx_epoll_module; extern ngx_module_t ngx_regex_module; extern ngx_module_t ngx_http_module; extern ngx_module_t ngx_http_core_module; extern ngx_module_t ngx_http_log_module; extern ngx_module_t ngx_http_upstream_module; extern ngx_module_t ngx_http_static_module; extern ngx_module_t ngx_http_autoindex_module; extern ngx_module_t ngx_http_index_module; ... ngx_module_t *ngx_modules[] = { &ngx_core_module, &ngx_errlog_module, &ngx_conf_module, &ngx_events_module, &ngx_event_core_module, &ngx_epoll_module, &ngx_regex_module, &ngx_http_module, &ngx_http_core_module, &ngx_http_log_module, &ngx_http_upstream_module, &ngx_http_static_module, &ngx_http_autoindex_module, &ngx_http_index_module, ... NULL };
因爲數組存放的是同一類型的數據。所以,必須有一個模塊基類來抽象的定義全部模塊。這個抽象基類就是ngx_module_t
。
所以,能夠看到ngx_modules
數組裏存放的是ngx_module_t *
類型指針,而且,最後一個必定是空指針NULL
。
將最後一個元素置爲空指針NULL
,是爲了遍歷數組的時候,標記數組結束,這樣沒必要在使用時記錄數組大小。
例如:
for (i = 0; ngx_modules[i]; i++) { ... }
使用extern ngx_module_t ngx_core_module;
使編譯器在編譯的時候不去處理ngx_core_module
,在連接階段,再將ngx_core_module
連接到正確的地址中。
相似地,在源文件core\ngx_conf_file.h
的末尾聲明外部ngx_modules[]
extern ngx_module_t *ngx_modules[];
因爲core\ngx_conf_file.h
會被看成公共頭文件被包含到其餘文件中,所以,ngx_modules
是一個全局變量。
======分割線=======
在編譯階段,objs\ngx_modules.c
文件中的那一堆extern變量及ngx_modules
變量都會被初始化。緣由在於,這些變量都屬於全局變量,將會被靜態初始化。
======分割線=======
這樣,有了全局數組ngx_modules
,就能夠獲取全部模塊的指針,從而操做全部模塊。對全部模塊的管理和操做也由此展開。
全部模塊都是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; };
各成員變量含義以下:
1. type
type
變量是指模塊的類型。Nginx
中模塊的類型定義以下:
#define NGX_CORE_MODULE 0x45524F43 /* "CORE" */ #define NGX_CONF_MODULE 0x464E4F43 /* "CONF" */ #define NGX_EVENT_MODULE 0x544E5645 /* "EVNT" */ #define NGX_HTTP_MODULE 0x50545448 /* "HTTP" */ #define NGX_MAIL_MODULE 0x4C49414D /* "MAIL" */
也就是說,Nginx
共有5中模塊類型CORF
、CONF
、EVNT
、HTTP
、MAIL
。
2. index
index
變量是指,該模塊在ngx_modules
數組中的次序,或者說下標。該變量在Nginx
執行初始化的時候被初始化,初始化代碼位於core\nginx.c
的main
函數中:
ngx_max_module = 0; for (i = 0; ngx_modules[i]; i++) { ngx_modules[i]->index = ngx_max_module++; }
3. ctx_index
ctx_index
是指,在ngx_modules
數組中,該模塊在相同類型的模塊中的次序。
例如,ngx_modules
數組中有多個類型爲NGX_EVENT_MODULE
的模塊,那麼其中一個模塊的ctx_index
初始化以下:
// 源碼文件event\ngx_event.c ngx_event_max_module = 0; for (i = 0; ngx_modules[i]; i++) { if (ngx_modules[i]->type != NGX_EVENT_MODULE) { continue; } ngx_modules[i]->ctx_index = ngx_event_max_module++; }
4. ctx
ctx
是void *
指針型變量,這是指向與模塊相關的上下文。
這裏先解釋一下什麼叫與模塊相關的上下文。
上下文這個概念通常能夠理解爲運行環境,那麼與模塊相關的上下文就是指模塊運行環境。換句話說,就是一些參數的配置信息。由於配置通常意味着設置,而設置的對象就是模塊的運行環境。好比,ngx_core_modules
運行時的user
和group
,就屬於運行環境,同時,也屬於配置項。
因爲模塊的參數通常比較多,正確設置參數的配置須要不少操做。因此,上下文其實也意味着一組操做,這組操做的目的在於根據配置,正確設置模塊的參數信息。同時,這也意味着,不一樣的模塊,這組操做是不一樣的,所以,這裏須要將ctx
設置爲void *
指針,來進行泛型的操做。
以ngx_core_module
爲例,其ctx
指向的上下文是這個樣子的:
static ngx_core_module_t ngx_core_module_ctx = { ngx_string("core"), ngx_core_module_create_conf, ngx_core_module_init_conf };
其中ngx_core_module_t
的定義以下:
typedef struct { ngx_str_t name; void *(*create_conf)(ngx_cycle_t *cycle); char *(*init_conf)(ngx_cycle_t *cycle, void *conf); } ngx_core_module_t;
而這組操做中的ngx_core_module_init_conf
函數中,初始化了一個ngx_core_conf_t
的結構體。
所以,可知,void *ctx
指向了一組操做,這組操做的目的在於初始化一個與模塊配置信息相關的結構體。
這裏涉及到了三個結構體:
ngx_module_t ngx_core_module
:用來表示模塊自己,保存在ngx_modules
數組中;ngx_core_conf_t core_conf
:用來保存對該模塊的配置信息;ngx_core_module_t ngx_core_module_ctx
:用來初始化ngx_core_conf_t
中的成員變量;6. commands
commands是ngx_command_t
數組,表示一組配置文件中的可配項(指令)。
例如,在配置文件nginx.conf
中worker_processes 1;
對應commands
數組中的一項,該項的定義以下,類型爲ngx_command_t
:
{ ngx_string("worker_processes"), NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_TAKE1, ngx_set_worker_processes, 0, 0, NULL }
其中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; };
因此,commands
的含義在於該模塊的配置項在配置文件中的指令。
到這裏,一個完整的模塊所需的各個部分逐漸顯露出來了:
ngx_module_t
結構體,用來表示模塊的定義,被放入ngx_modules
數組中。ngx_<module name>_conf_t
結構體,用來表示模塊的配置項,這個結構體隨模塊的不一樣而不一樣,經過上下文操做及commands中定義的指令,由配置文件肯定其成員值。ngx_<module>_module_t
結構體,表示一組用來初始化ngx_<module name>_conf_t
結構體的操做。在Nginx
初始化時被調用,初始化ngx_<module name>_conf_t
結構體。ngx_command_t
結構體數組,用來表示該模塊能夠在配置文件中配置的項目,及其操做指令。在Nginx
初始化解析配置文件後,調用ngx_command_t
中的函數set
初始化ngx_<module name>_conf_t
結構體。在Nginx
中,一個模塊運行所需的各類配置參數被封裝成了ngx_<module name>_conf_t
結構體。
這個結構體內成員變量的初始化被分紅了兩部分:
ngx_<module>_module_t
:即定義了一組初始化操做,用來將該結構體內的各成員初始化。ngx_command_t
:即規定了配置文件中可使用的指令及其對應的操做函數。而模塊自己被封裝成了ngx_module_t
類型結構體,被用來供Nginx
統一管理和使用。
模塊和配置的聯繫很是緊密,所以,這裏僅僅先大略的分析一下模塊功能的總體框架,下一篇中,將在本篇的基礎上分析Nginx
的配置功能。