Nginx 模塊自主開發四: 模塊數據結構

其中,ngx_module_s,這 個是 每個新的模塊的定義

struct ngx_module_s {
   /*ctx_index表示當前模塊在這類模塊中的序號。這個 成員常常是由管理模塊的 一個Nginx核心模塊設置的,對於所有的http模塊而言,ctx_index是由核心模塊ngx_http_module設置的,ctx_index非常重要,Nginx的模塊化設計非常依賴各個模塊的順序*/
    ngx_uint_t            ctx_index;
    /*index表示當前模塊在ngx_modules數組中 的序號。*/
    ngx_uint_t            index; 

    char                 *name;
    // sqare系列的 保留變量,暫未使用
    ngx_uint_t            spare0;
    ngx_uint_t            spare1;
    // 模塊的版本
    ngx_uint_t            version;
    const char           *signature;
   /**ctx用於指向一類的模塊的上下文結構體,Nginx模塊有許多種類,不同模塊之間的功能差別很大。例如事件模塊主要處理I/O事件相關的功能,每個模塊都有自己的特性,ctx將會指向特定類型模塊的公共接口,例如在Http 模塊 中,ctxz指向ngx_http_module_t結構體*/
    void                 *ctx;
    // commands將處理nginx.conf中 的配置項
    ngx_command_t        *commands;
    /*type 表示該模塊的類型,它與ctx指針是緊密相關的,NGX_HTTP_MODULE、NGX_CORE_MODULE、NGX_CONF_MODULE、NGX_EVENT_MODULE、NGX_EVENT_MODULE、NGX_STREAM_MODULE*/
    ngx_uint_t            type;
    /*在Nginx 啓動、停止過程中,以下7個函數指針表示有7個執行點分別調用這個7個方法,對於任一方法,如果不需要Nginx在某個時刻執行 它,那麼 簡單地把它設爲NULL空指針 即可*/
    /* 雖然字面上理解應當在master進程啓動時調用,但到目前爲止,框架代碼從來不會調用它,因此 要設爲NULL*/
    ngx_int_t           (*init_master)(ngx_log_t *log);
    /*init module 回調方法在初始化所有模塊被調用,在master/worker模式下,這個階段將在worker進程前完成 */
    ngx_int_t           (*init_module)(ngx_cycle_t *cycle);
   /*init_process回調方法在正常服務前被調用,在master/worker模式下,多個worker子進程已經產生,在每個worker進程初始化會調用所有模塊的init_process函數*/
    ngx_int_t           (*init_process)(ngx_cycle_t *cycle);
    // Nginx目前還支持多線程,所以這個沒有被調用過
    ngx_int_t           (*init_thread)(ngx_cycle_t *cycle);
    void                (*exit_thread)(ngx_cycle_t *cycle);
   /* exit_process回調方法在服務停止前調用。在master/worker模式下,worker會在退出前調用它*/
    void                (*exit_process)(ngx_cycle_t *cycle);
    //該方法 會在master進程退出前調用它
    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;
};

回調方法:init_module、init_process、exit_process、exit_master,調用它們是Nginx 的 框架代碼 。

所以定義模塊的 時候,最重要的就是要設置ctx和commands 這兩個成員。ctx指向的 是相應的接口(結構 體 )。框架會在讀取、重新配置文件定義了ctx指向的接口描述 的 幾個階段,框架會在啓動過程中調接口中定義的相應方法。如果相應的某個回調函數設爲NULL,那麼框架不會調用這個回調。

下面 我舉一個ctx指向的ngx_http_module_t結構體 (不同模塊指向不一樣)


typedef struct {
     // 解析配置文件前函數調用 
    ngx_int_t   (*preconfiguration)(ngx_conf_t *cf);
    // 完成配置文件的解析後調用
    ngx_int_t   (*postconfiguration)(ngx_conf_t *cf);
    /*當需要創建數據結構用於存儲main級別(直屬http{...}塊的配置項)的 全局配置 項時,可以通過這個回調方法 創建存儲全局配置項的結構體*/
    void       *(*create_main_conf)(ngx_conf_t *cf);
    // 常用於初始化main級別配置項
    char       *(*init_main_conf)(ngx_conf_t *cf, void *conf);
    /*當需要創建數據結構用於存儲srv級別(直屬於虛擬機server{}塊配置項),可以通過通過實現這個方法創建srv級別配置項的結構體*/
    void       *(*create_srv_conf)(ngx_conf_t *cf);
    //合併main級別和srv級別下的同名配置
    char       *(*merge_srv_conf)(ngx_conf_t *cf, void *prev, void *conf);
    /*當需要創建數據結構用於存儲loc級別的(直屬於location{}塊 配置項)*/
    void       *(*create_loc_conf)(ngx_conf_t *cf);
    // 合併serv級別和loc級別下的同名配置
    char       *(*merge_loc_conf)(ngx_conf_t *cf, void *prev, void *conf);
} ngx_http_module_t;

說完 了ctx接口 ,接下來我們 進入另一個核心的結構commands

commands數組是用於定義模塊配置文件的參數,每一個數組元素都是ngx_command_t類型,數組的結尾用ngx__null_command表示,Nginx在解析 配置文件中一個 配置項時,首先會遍歷所有模塊,對於每一個模塊而言,即通過遍歷commands數組進行 ,在數組中檢查到 ngx_null_command,就會停止當前模塊解析該 配置項。

struct ngx_command_s {
    // 配置項的名稱 比如 "http"
    ngx_str_t             name;
    /*配置項類型,type將 指定配置項可以出現的位置,例如出現在server{}或location{}中,已經他可以攜帶參數的個數*/
    ngx_uint_t            type;
    // 出現了name指定的配置項後,將會調用set方法處理該配置項的參數
    char               *(*set)(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
    //在配置項中的偏移量 
    ngx_uint_t            conf;
    //和conf參數配合使用
    ngx_uint_t            offset;
    //配置項讀取配置的處理方法 ,必須是ngx_conf_post_t結構的指針
    void                 *post;
};

ngx_null_command只是 一個空的ngx_command_t

#define ngx_null_command  { ngx_null_string, 0, NULL, 0, 0, NULL }

下面是一個command定義的例子

static ngx_command_t ngx_http_circle_gif_commands[] = {
{ ngx_string("circle_gif"),
NGX_HTTP_LOC_CONF|NGX_CONF_NOARGS,
ngx_http_circle_gif,
NGX_HTTP_LOC_CONF_OFFSET,
0,
NULL },
{ ngx_string("circle_gif_min_radius"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|
NGX_CONF_TAKE1,
ngx_conf_set_num_slot,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_circle_gif_loc_conf_t, min_radius),
NULL },
...
ngx_null_command
};

type選項

type參數 含義
NGX_HTTP_MAIN_CON 指令出現在全局配置部分是合法的
NGX_HTTP_SRV_CONF 指令在主機配置部分出現是合法的
NGX_HTTP_LOC_CONF 指令在位置配置部分出現是合法的
NGX_HTTP_UPS_CONF 指令在上游服務器配置部分出現是合法的
NGX_CONF_NOARGS 指令沒有參數
NGX_CONF_TAKE1 指令讀入一個參數
NGX_CONF_TAKE2 指令讀入兩個參數
….. …..
NGX_CONF_TAKE7 指令讀入七個參數
NGX_CONF_FLAG 指令讀入一個布爾型數據
NGX_CONF_1MORE 指令至少讀入 1 個參數
NGX_CONF_2MORE 指令至少讀入 2 個參數

總結

nginx 主進程在啓動時,就會在代碼裏面找相應的ngx_module_t(ngx_XXX_module)變量,找到以後,在其中ngx_command_t(ngx_xxx_commands)指定函數ngx
_xxx_init開始初始化模塊。所有的工作都要在這裏進行。

Nginx啓動時,會先啓動一個master管理進程,然後根據配置啓動數個worker進程。實際的module裏的勾子函數(例如ngx_XXX_handle),都是被worker進程所調用的。默認情況下,nginx並不是多線程的,所以,如果你的勾子函數被調用了,那麼你絕對不可以有任何阻塞操作,否則會使得nginx worker不去處理已經在鏈表中的其他connection,這就完全毀了nginx,如果你去同步請求硬盤IO資源,否則其他SERVER的網絡IO,那麼它和apach+CGI這種低性能SERVER也沒啥兩樣了,除了epoll可以hold住大量連接。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章