<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ThinkChat2.0新版上線,更智能更精彩,支持會話、畫圖、視頻、閱讀、搜索等,送10W Token,即刻開啟你的AI之旅 廣告
                ### 概述 ? ? ? Nginx 是以事件的觸發來驅動的,事件驅動模型主要包括事件收集、事件發送、事件處理(即事件管理)三部分。在Nginx 的工作進程中主要關注的事件是IO 網絡事件 和 定時器事件。在生成的 objs 目錄文件中,其中ngx_modules.c 文件的內容是Nginx 各種模塊的執行順序,我們可以從該文件的內容中看到事件模塊的執行順序為以下所示:注意:由于是在Linux 系統下,所以支持具體的 epoll 事件模塊,接下來的文章結構按照以下順序來寫。 ~~~ extern ngx_module_t ngx_events_module; extern ngx_module_t ngx_event_core_module; extern ngx_module_t ngx_epoll_module; ~~~ ### 事件模塊接口 ### ngx_event_module_t 結構體 ? ? ? 在 Nginx 中,結構體 ngx_module_t 是 Nginx 模塊最基本的接口。對于每一種不同類型的模塊,都有一個具體的結構體來描述這一類模塊的通用接口,該接口由ngx_module_t 中的成員ctx 管理。在 Nginx 中定義了事件模塊的通用接口ngx_event_module_t 結構體,該結構體定義在文件[src/event/ngx_event.h](http://lxr.nginx.org/source/src/event/ngx_event.h) 中: ~~~ /* 事件驅動模型通用接口ngx_event_module_t結構體 */ typedef struct { /* 事件模塊名稱 */ ngx_str_t *name; /* 解析配置項前調用,創建存儲配置項參數的結構體 */ void *(*create_conf)(ngx_cycle_t *cycle); /* 完成配置項解析后調用,處理當前事件模塊感興趣的全部配置 */ char *(*init_conf)(ngx_cycle_t *cycle, void *conf); /* 每個事件模塊具體實現的方法,有10個方法,即IO多路復用模型的統一接口 */ ngx_event_actions_t actions; } ngx_event_module_t; ~~~ ? ? ? 在 ngx_event_module_t 結構體中actions 的類型是ngx_event_actions_t 結構體,該成員結構實現了事件驅動模塊的具體方法。該結構體定義在文件[src/event/ngx_event.h](http://lxr.nginx.org/source/src/event/ngx_event.h) 中: ~~~ /* IO多路復用模型的統一接口 */ typedef struct { /* 添加事件,將某個描述符的某個事件添加到事件驅動機制監控描述符集中 */ ngx_int_t (*add)(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags); /* 刪除事件,將某個描述符的某個事件從事件驅動機制監控描述符集中刪除 */ ngx_int_t (*del)(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags); /* 啟動對某個指定事件的監控 */ ngx_int_t (*enable)(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags); /* 禁用對某個指定事件的監控 */ ngx_int_t (*disable)(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags); /* 將指定連接所關聯的描述符添加到事件驅動機制監控中 */ ngx_int_t (*add_conn)(ngx_connection_t *c); /* 將指定連接所關聯的描述符從事件驅動機制監控中刪除 */ ngx_int_t (*del_conn)(ngx_connection_t *c, ngx_uint_t flags); /* 監控事件是否發生變化,僅用在多線程環境中 */ ngx_int_t (*process_changes)(ngx_cycle_t *cycle, ngx_uint_t nowait); /* 等待事件的發生,并對事件進行處理 */ ngx_int_t (*process_events)(ngx_cycle_t *cycle, ngx_msec_t timer, ngx_uint_t flags); /* 初始化事件驅動模塊 */ ngx_int_t (*init)(ngx_cycle_t *cycle, ngx_msec_t timer); /* 在退出事件驅動模塊前調用該函數回收資源 */ void (*done)(ngx_cycle_t *cycle); } ngx_event_actions_t; ~~~ ### ngx_event_t 結構體 ? ? ? 在 Nginx 中,每一個具體事件的定義由結構體ngx_event_t 來表示,該結構體ngx_event_t 用來保存具體事件。該結構體定義在文件 [src/event/ngx_event.h](http://lxr.nginx.org/source/src/event/ngx_event.h) 中: ~~~ /* 描述每一個事件的ngx_event_t結構體 */ struct ngx_event_s { /* 事件相關對象的數據,通常指向ngx_connect_t連接對象 */ void *data; /* 標志位,為1表示事件可寫,即當前對應的TCP連接狀態可寫 */ unsigned write:1; /* 標志位,為1表示事件可以建立新連接 */ unsigned accept:1; /* used to detect the stale events in kqueue, rtsig, and epoll */ unsigned instance:1; /* * the event was passed or would be passed to a kernel; * in aio mode - operation was posted. */ /* 標志位,為1表示事件處于活躍狀態 */ unsigned active:1; /* 標志位,為1表示禁用事件 */ unsigned disabled:1; /* the ready event; in aio mode 0 means that no operation can be posted */ /* 標志位,為1表示當前事件已經準備就緒 */ unsigned ready:1; /* 該標志位只用于kqueue,eventport模塊,對Linux上的驅動模塊沒有任何意義 */ unsigned oneshot:1; /* aio operation is complete */ /* 該標志位用于異步AIO事件處理 */ unsigned complete:1; /* 標志位,為1表示當前處理的字符流已經結束 */ unsigned eof:1; /* 標志位,為1表示當前事件處理過程中出錯 */ unsigned error:1; /* 標志位,為1表示當前事件已超時 */ unsigned timedout:1; /* 標志位,為1表示當前事件存在于定時器中 */ unsigned timer_set:1; /* 標志位,為1表示當前事件需要延遲處理 */ unsigned delayed:1; /* * 標志位,為1表示TCP建立需要延遲,即完成建立TCP連接的三次握手后, * 不會立即建立TCP連接,直到接收到數據包才建立TCP連接; */ unsigned deferred_accept:1; /* the pending eof reported by kqueue, epoll or in aio chain operation */ /* 標志位,為1表示等待字符流結束 */ unsigned pending_eof:1; /* 標志位,為1表示處理post事件 */ unsigned posted:1; #if (NGX_WIN32) /* setsockopt(SO_UPDATE_ACCEPT_CONTEXT) was successful */ unsigned accept_context_updated:1; #endif #if (NGX_HAVE_KQUEUE) unsigned kq_vnode:1; /* the pending errno reported by kqueue */ int kq_errno; #endif /* * kqueue only: * accept: number of sockets that wait to be accepted * read: bytes to read when event is ready * or lowat when event is set with NGX_LOWAT_EVENT flag * write: available space in buffer when event is ready * or lowat when event is set with NGX_LOWAT_EVENT flag * * iocp: TODO * * otherwise: * accept: 1 if accept many, 0 otherwise */ #if (NGX_HAVE_KQUEUE) || (NGX_HAVE_IOCP) int available; #else /* 標志位,在epoll事件機制中表示一次盡可能多地建立TCP連接 */ unsigned available:1; #endif /* 當前事件發生時的處理方法 */ ngx_event_handler_pt handler; #if (NGX_HAVE_AIO) #if (NGX_HAVE_IOCP) ngx_event_ovlp_t ovlp; #else /* Linux系統aio機制中定義的結構體 */ struct aiocb aiocb; #endif #endif /* epoll機制不使用該變量 */ ngx_uint_t index; /* 日志記錄 */ ngx_log_t *log; /* 定時器 */ ngx_rbtree_node_t timer; /* the posted queue */ ngx_queue_t queue; /* 標志位,為1表示當前事件已經關閉 */ unsigned closed:1; /* to test on worker exit */ unsigned channel:1; unsigned resolver:1; unsigned cancelable:1; #if 0 /* the threads support */ /* * the event thread context, we store it here * if $(CC) does not understand __thread declaration * and pthread_getspecific() is too costly */ void *thr_ctx; #if (NGX_EVENT_T_PADDING) /* event should not cross cache line in SMP */ uint32_t padding[NGX_EVENT_T_PADDING]; #endif #endif }; ~~~ ? ? ? 在每個事件結構體 ngx_event_t 最重要的成員是handler 回調函數,該回調函數定義了當事件發生時的處理方法。該回調方法原型在文件[src/core/ngx_core.h](http://lxr.nginx.org/source/src/core/ngx_core.h) 中: ~~~ typedef void (*ngx_event_handler_pt)(ngx_event_t *ev); ~~~ ### ngx_connection_t 結構體 ? ? ? 當客戶端向 Nginx 服務器發起連接請求時,此時若Nginx 服務器被動接收該連接,則相對Nginx 服務器來說稱為被動連接,被動連接的表示由基本數據結構體ngx_connection_t 完成。該結構體定義在文件 [src/core/ngx_connection.h](http://lxr.nginx.org/source/src/core/ngx_connection.h) 中: ~~~ /* TCP連接結構體 */ struct ngx_connection_s { /* * 當Nginx服務器產生新的socket時, * 都會創建一個ngx_connection_s 結構體, * 該結構體用于保存socket的屬性和數據; */ /* * 當連接未被使用時,data充當連接池中空閑連接表中的next指針; * 當連接被使用時,data的意義由具體Nginx模塊決定; */ void *data; /* 設置該鏈接的讀事件 */ ngx_event_t *read; /* 設置該連接的寫事件 */ ngx_event_t *write; /* 用于設置socket的套接字描述符 */ ngx_socket_t fd; /* 接收網絡字符流的方法,是一個函數指針,指向接收函數 */ ngx_recv_pt recv; /* 發送網絡字符流的方法,是一個函數指針,指向發送函數 */ ngx_send_pt send; /* 以ngx_chain_t鏈表方式接收網絡字符流的方法 */ ngx_recv_chain_pt recv_chain; /* 以ngx_chain_t鏈表方式發送網絡字符流的方法 */ ngx_send_chain_pt send_chain; /* * 當前連接對應的ngx_listening_t監聽對象, * 當前連接由ngx_listening_t成員的listening監聽端口的事件建立; * 成員connection指向當前連接; */ ngx_listening_t *listening; /* 當前連接已發生的字節數 */ off_t sent; /* 記錄日志 */ ngx_log_t *log; /* 內存池 */ ngx_pool_t *pool; /* 對端的socket地址sockaddr屬性*/ struct sockaddr *sockaddr; socklen_t socklen; /* 字符串形式的IP地址 */ ngx_str_t addr_text; ngx_str_t proxy_protocol_addr; #if (NGX_SSL) ngx_ssl_connection_t *ssl; #endif /* 本端的監聽端口對應的socket的地址sockaddr屬性 */ struct sockaddr *local_sockaddr; socklen_t local_socklen; /* 用于接收、緩存對端發來的字符流 */ ngx_buf_t *buffer; /* * 表示將當前連接作為雙向連接中節點元素, * 添加到ngx_cycle_t結構體的成員 * reuseable_connections_queue的雙向鏈表中; */ ngx_queue_t queue; /* 連接使用次數 */ ngx_atomic_uint_t number; /* 處理請求的次數 */ ngx_uint_t requests; unsigned buffered:8; unsigned log_error:3; /* ngx_connection_log_error_e */ /* 標志位,為1表示不期待字符流結束 */ unsigned unexpected_eof:1; /* 標志位,為1表示當前連接已經超時 */ unsigned timedout:1; /* 標志位,為1表示處理連接過程出錯 */ unsigned error:1; /* 標志位,為1表示當前TCP連接已經銷毀 */ unsigned destroyed:1; /* 標志位,為1表示當前連接處于空閑狀態 */ unsigned idle:1; /* 標志位,為1表示當前連接可重用 */ unsigned reusable:1; /* 標志為,為1表示當前連接已經關閉 */ unsigned close:1; /* 標志位,為1表示正在將文件的數據發往對端 */ unsigned sendfile:1; /* * 標志位,若為1,則表示只有連接對應的發送緩沖區滿足最低設置的閾值時, * 事件驅動模塊才會分發事件; */ unsigned sndlowat:1; unsigned tcp_nodelay:2; /* ngx_connection_tcp_nodelay_e */ unsigned tcp_nopush:2; /* ngx_connection_tcp_nopush_e */ unsigned need_last_buf:1; #if (NGX_HAVE_IOCP) unsigned accept_context_updated:1; #endif #if (NGX_HAVE_AIO_SENDFILE) /* 標志位,為1表示使用異步IO方式將磁盤文件發送給網絡連接的對端 */ unsigned aio_sendfile:1; unsigned busy_count:2; /* 使用異步IO發送文件時,用于待發送的文件信息 */ ngx_buf_t *busy_sendfile; #endif #if (NGX_THREADS) ngx_atomic_t lock; #endif }; ~~~ ? ? ? 在處理請求的過程中,若 Nginx 服務器主動向上游服務器建立連接,完成連接建立并與之進行通信,這種相對Nginx 服務器來說是一種主動連接,主動連接由結構體ngx_peer_connection_t 表示,但是該結構體 ngx_peer_connection_t 也是 ngx_connection_t 結構體的封裝。該結構體定義在文件[src/event/ngx_event_connect.h](http://lxr.nginx.org/source/src/event/ngx_event_connect.h) 中: ~~~ /* 主動連接的結構體 */ struct ngx_peer_connection_s { /* 這里是對ngx_connection_t連接結構體的引用 */ ngx_connection_t *connection; /* 遠端服務器的socket的地址sockaddr信息 */ struct sockaddr *sockaddr; socklen_t socklen; /* 遠端服務器的名稱 */ ngx_str_t *name; /* 連接重試的次數 */ ngx_uint_t tries; /* 獲取連接的方法 */ ngx_event_get_peer_pt get; /* 釋放連接的方法 */ ngx_event_free_peer_pt free; /* 配合get、free使用 */ void *data; #if (NGX_SSL) ngx_event_set_peer_session_pt set_session; ngx_event_save_peer_session_pt save_session; #endif #if (NGX_THREADS) ngx_atomic_t *lock; #endif /* 本地地址信息 */ ngx_addr_t *local; /* 接收緩沖區 */ int rcvbuf; /* 記錄日志 */ ngx_log_t *log; /* 標志位,為1表示connection連接已經緩存 */ unsigned cached:1; /* ngx_connection_log_error_e */ unsigned log_error:2; }; ~~~ ### ngx_events_module?核心模塊 ### ngx_events_module?核心模塊的定義 ? ? ? ngx_events_module 模塊是事件的核心模塊,該模塊的功能是:定義新的事件類型,并為每個事件模塊定義通用接口ngx_event_module_t 結構體,管理事件模塊生成的配置項結構體,并解析事件類配置項。首先,看下該模塊在文件[src/event/ngx_event.c](http://lxr.nginx.org/source/src/event/ngx_event.c) 中的定義: ~~~ /* 定義事件核心模塊 */ ngx_module_t ngx_events_module = { NGX_MODULE_V1, &ngx_events_module_ctx, /* module context */ ngx_events_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_events_commands 決定了該模塊的功能。配置項指令結構ngx_events_commands 在文件[src/event/ngx_event.c](http://lxr.nginx.org/source/src/event/ngx_event.c) 中定義如下: ~~~ /* 配置項結構體數組 */ static ngx_command_t ngx_events_commands[] = { { ngx_string("events"), NGX_MAIN_CONF|NGX_CONF_BLOCK|NGX_CONF_NOARGS, ngx_events_block, 0, 0, NULL }, ngx_null_command }; ~~~ ? ? ? 從配置項結構體中可以知道,該模塊只對 events{...} 配置塊感興趣,并定義了管理事件模塊的方法ngx_events_block;ngx_events_block 方法在文件[src/event/ngx_event.c](http://lxr.nginx.org/source/src/event/ngx_event.c) 中定義: ~~~ /* 管理事件模塊 */ static char * ngx_events_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { char *rv; void ***ctx; ngx_uint_t i; ngx_conf_t pcf; ngx_event_module_t *m; if (*(void **) conf) { return "is duplicate"; } /* count the number of the event modules and set up their indices */ /* 計算模塊類中模塊的總數,并初始化模塊在模塊類中的序號 */ 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++; } ctx = ngx_pcalloc(cf->pool, sizeof(void *)); if (ctx == NULL) { return NGX_CONF_ERROR; } /* 分配指針數組,用于存儲所有事件模塊生成的配置項結構體指針 */ *ctx = ngx_pcalloc(cf->pool, ngx_event_max_module * sizeof(void *)); if (*ctx == NULL) { return NGX_CONF_ERROR; } *(void **) conf = ctx; /* 若是事件模塊,并且定義了create_conf方法,則調用該方法創建存儲配置項參數的結構體 */ for (i = 0; ngx_modules[i]; i++) { if (ngx_modules[i]->type != NGX_EVENT_MODULE) { continue; } m = ngx_modules[i]->ctx; if (m->create_conf) { (*ctx)[ngx_modules[i]->ctx_index] = m->create_conf(cf->cycle); if ((*ctx)[ngx_modules[i]->ctx_index] == NULL) { return NGX_CONF_ERROR; } } } /* 初始化配置項結構體cf */ pcf = *cf; cf->ctx = ctx;/* 描述事件模塊的配置項結構 */ cf->module_type = NGX_EVENT_MODULE;/* 當前解析指令的模塊類型 */ cf->cmd_type = NGX_EVENT_CONF;/* 當前解析指令的指令類型 */ /* 為所有事件模塊解析配置文件nginx.conf中的event{}塊中的指令 */ rv = ngx_conf_parse(cf, NULL); *cf = pcf; if (rv != NGX_CONF_OK) return rv; /* 遍歷所有事件模塊,若定義了init_conf方法,則調用該方法用于處理事件模塊感興趣的配置項 */ for (i = 0; ngx_modules[i]; i++) { if (ngx_modules[i]->type != NGX_EVENT_MODULE) { continue; } m = ngx_modules[i]->ctx; if (m->init_conf) { rv = m->init_conf(cf->cycle, (*ctx)[ngx_modules[i]->ctx_index]); if (rv != NGX_CONF_OK) { return rv; } } } return NGX_CONF_OK; } ~~~ ? ? ? 另外,在 ngx_events_module 模塊的定義中有一個成員ctx 指向了核心模塊的通用接口結構。核心模塊的通用接口結構體定義在文件[src/core/ngx_conf_file.h](http://lxr.nginx.org/source/src/core/ngx_conf_file.h) 中: ~~~ /* 核心模塊的通用接口結構體 */ 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_events_module 作為核心模塊,必須定義核心模塊的通用接口結構。ngx_events_module 模塊的核心模塊通用接口在文件[src/event/ngx_event.c](http://lxr.nginx.org/source/src/event/ngx_event.c) 中定義: ~~~ /* 實現核心模塊通用接口 */ static ngx_core_module_t ngx_events_module_ctx = { ngx_string("events"), NULL, /* * 以前的版本這里是NULL,現在實現了一個獲取events配置項的函數,* * 但是沒有什么作用,因為每個事件模塊都會去獲取events配置項, * 并進行解析與處理; */ ngx_event_init_conf }; ~~~ ### 所有事件模塊的配置項管理 ? ? ? Nginx 服務器在結構體 ngx_cycle_t 中定義了一個四級指針成員 conf_ctx,整個Nginx 模塊都是使用該四級指針成員管理模塊的配置項結構,以下events 模塊為例對該四級指針成員進行簡單的分析,如下圖所示: ![](https://box.kancloud.cn/2016-09-01_57c7edd0daba6.jpg) ? ? ? 每個事件模塊可以通過宏定義 ngx_event_get_conf 獲取它在create_conf 中分配的結構體的指針;該宏中定義如下: ~~~ #define ngx_event_get_conf(conf_ctx, module) \ (*(ngx_get_conf(conf_ctx, ngx_events_module))) [module.ctx_index]; /* 其中 ngx_get_conf 定義如下 */ #define ngx_get_conf(conf_ctx, module) conf_ctx[module.index] ~~~ ? ? ? 從上面的宏定義可以知道,每個事件模塊獲取自己在 create_conf 中分配的結構體的指針,只需在ngx_event_get_conf 傳入參數ngx_cycle_t 中的 conf_ctx 成員,并且傳入自己模塊的名稱即可獲取自己分配的結構體指針。 ### ngx_event_core_module 事件模塊 ? ? ? ngx_event_core_module 模塊是一個事件類型的模塊,它在所有事件模塊中的順序是第一,是其它事件類模塊的基礎。它主要完成以下任務: 1. 創建連接池; 1. 決定使用哪些事件驅動機制; 1. 初始化將要使用的事件模塊; ### ngx_event_conf_t 結構體 ? ? ? ngx_event_conf_t 結構體是用來保存ngx_event_core_module 事件模塊配置項參數的。該結構體在文件[src/event/ngx_event.h](http://lxr.nginx.org/source/src/event/ngx_event.h) 中定義: ~~~ /* 存儲ngx_event_core_module事件模塊配置項參數的結構體 ngx_event_conf_t */ typedef struct { /* 連接池中最大連接數 */ ngx_uint_t connections; /* 被選用模塊在所有事件模塊中的序號 */ ngx_uint_t use; /* 標志位,為1表示可批量建立連接 */ ngx_flag_t multi_accept; /* 標志位,為1表示打開負載均衡鎖 */ ngx_flag_t accept_mutex; /* 延遲建立連接 */ ngx_msec_t accept_mutex_delay; /* 被使用事件模塊的名稱 */ u_char *name; #if (NGX_DEBUG) /* 用于保存與輸出調試級別日志連接對應客戶端的地址信息 */ ngx_array_t debug_connection; #endif } ngx_event_conf_t; ~~~ ### ngx_event_core_module 事件模塊的定義 ? ? ? 該模塊在文件 [src/event/ngx_event.c](http://lxr.nginx.org/source/src/event/ngx_event.c) 中定義: ~~~ /* 事件模塊的定義 */ ngx_module_t ngx_event_core_module = { NGX_MODULE_V1, &ngx_event_core_module_ctx, /* module context */ ngx_event_core_commands, /* module directives */ NGX_EVENT_MODULE, /* module type */ NULL, /* init master */ ngx_event_module_init, /* init module */ ngx_event_process_init, /* init process */ NULL, /* init thread */ NULL, /* exit thread */ NULL, /* exit process */ NULL, /* exit master */ NGX_MODULE_V1_PADDING }; ~~~ ? ? ? 其中,模塊的配置項指令結構?ngx_event_core_commands?決定了該模塊的功能。配置項指令結構?ngx_event_core_commands?在文件?[src/event/ngx_event.c](http://lxr.nginx.org/source/src/event/ngx_event.c)?中定義如下: ~~~ static ngx_str_t event_core_name = ngx_string("event_core"); /* 定義ngx_event_core_module 模塊感興趣的配置項 */ static ngx_command_t ngx_event_core_commands[] = { /* 每個worker進程中TCP最大連接數 */ { ngx_string("worker_connections"), NGX_EVENT_CONF|NGX_CONF_TAKE1, ngx_event_connections, 0, 0, NULL }, /* 與上面的worker_connections配置項相同 */ { ngx_string("connections"), NGX_EVENT_CONF|NGX_CONF_TAKE1, ngx_event_connections, 0, 0, NULL }, /* 選擇事件模塊作為事件驅動機制 */ { ngx_string("use"), NGX_EVENT_CONF|NGX_CONF_TAKE1, ngx_event_use, 0, 0, NULL }, /* 批量接收連接 */ { ngx_string("multi_accept"), NGX_EVENT_CONF|NGX_CONF_FLAG, ngx_conf_set_flag_slot, 0, offsetof(ngx_event_conf_t, multi_accept), NULL }, /* 是否打開accept_mutex負載均衡鎖 */ { ngx_string("accept_mutex"), NGX_EVENT_CONF|NGX_CONF_FLAG, ngx_conf_set_flag_slot, 0, offsetof(ngx_event_conf_t, accept_mutex), NULL }, /* 打開accept_mutex負載均衡鎖后,延遲處理新連接事件 */ { ngx_string("accept_mutex_delay"), NGX_EVENT_CONF|NGX_CONF_TAKE1, ngx_conf_set_msec_slot, 0, offsetof(ngx_event_conf_t, accept_mutex_delay), NULL }, /* 對指定IP的TCP連接打印debug級別的調試日志 */ { ngx_string("debug_connection"), NGX_EVENT_CONF|NGX_CONF_TAKE1, ngx_event_debug_connection, 0, 0, NULL }, ngx_null_command }; ~~~ ? ? ? 其中,每個事件模塊都需要實現事件模塊的通用接口結構 ngx_event_module_t,ngx_event_core_module?模塊的上下文結構?ngx_event_core_module_ctx?并不真正的負責網絡事件的驅動,所有不會實現ngx_event_module_t 結構體中的成員 actions 中的方法。上下文結構?ngx_event_core_module_ctx?在文件?[src/event/ngx_event.c](http://lxr.nginx.org/source/src/event/ngx_event.c)?中定義如下: ~~~ /* 根據事件模塊通用接口,實現ngx_event_core_module事件模塊的上下文結構 */ ngx_event_module_t ngx_event_core_module_ctx = { &event_core_name, ngx_event_core_create_conf, /* create configuration */ ngx_event_core_init_conf, /* init configuration */ { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL } }; ~~~ ? ? ? 在模塊定義中,實現了兩種方法分別為 ngx_event_module_init 和ngx_event_process_init 方法。在Nginx 啟動過程中沒有使用 fork 出 worker 子進程之前,先調用?ngx_event_core_module?模塊中的?ngx_event_module_init 方法,當fork 出 worker 子進程后,每一個 worker 子進程則會調用?ngx_event_process_init 方法。 ? ? ? ngx_event_module_init 方法在文件[src/event/ngx_event.c](http://lxr.nginx.org/source/src/event/ngx_event.c) 中定義: ~~~ /* 初始化事件模塊 */ static ngx_int_t ngx_event_module_init(ngx_cycle_t *cycle) { void ***cf; u_char *shared; size_t size, cl; ngx_shm_t shm; ngx_time_t *tp; ngx_core_conf_t *ccf; ngx_event_conf_t *ecf; /* 獲取存儲所有事件模塊配置結構的指針數據的首地址 */ cf = ngx_get_conf(cycle->conf_ctx, ngx_events_module); /* 獲取事件模塊ngx_event_core_module的配置結構 */ ecf = (*cf)[ngx_event_core_module.ctx_index]; /* 在錯誤日志中輸出被使用的事件模塊名稱 */ if (!ngx_test_config && ngx_process <= NGX_PROCESS_MASTER) { ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "using the \"%s\" event method", ecf->name); } /* 獲取模塊ngx_core_module的配置結構 */ ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module); ngx_timer_resolution = ccf->timer_resolution; #if !(NGX_WIN32) { ngx_int_t limit; struct rlimit rlmt; /* 獲取當前進程所打開的最大文件描述符個數 */ if (getrlimit(RLIMIT_NOFILE, &rlmt) == -1) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, "getrlimit(RLIMIT_NOFILE) failed, ignored"); } else { /* * 當前事件模塊的連接數大于最大文件描述符個數, * 或者大于由配置文件nginx.conf指定的worker_rlinit_nofile設置的最大文件描述符個數時, * 出錯返回; */ if (ecf->connections > (ngx_uint_t) rlmt.rlim_cur && (ccf->rlimit_nofile == NGX_CONF_UNSET || ecf->connections > (ngx_uint_t) ccf->rlimit_nofile)) { limit = (ccf->rlimit_nofile == NGX_CONF_UNSET) ? (ngx_int_t) rlmt.rlim_cur : ccf->rlimit_nofile; ngx_log_error(NGX_LOG_WARN, cycle->log, 0, "%ui worker_connections exceed " "open file resource limit: %i", ecf->connections, limit); } } } #endif /* !(NGX_WIN32) */ /* * 模塊ngx_core_module的master進程為0,表示不創建worker進程, * 則初始化到此結束,并成功返回; */ if (ccf->master == 0) { return NGX_OK; } /* * 若master不為0,且存在負載均衡鎖,則表示初始化完畢,并成功返回; */ if (ngx_accept_mutex_ptr) { return NGX_OK; } /* 不滿足以上兩個條件,則初始化下列變量 */ /* cl should be equal to or greater than cache line size */ /* 緩存行的大小 */ cl = 128; /* * 統計需要創建的共享內存大小; * ngx_accept_mutex用于多個worker進程之間的負載均衡鎖; * ngx_connection_counter表示nginx處理的連接總數; * ngx_temp_number表示在連接中創建的臨時文件個數; */ size = cl /* ngx_accept_mutex */ + cl /* ngx_connection_counter */ + cl; /* ngx_temp_number */ #if (NGX_STAT_STUB) /* * 下面表示某種情況的連接數; * ngx_stat_accepted 表示已成功建立的連接數; * ngx_stat_handled 表示已獲取ngx_connection_t結構并已初始化讀寫事件的連接數; * ngx_stat_requests 表示已被http模塊處理過的連接數; * ngx_stat_active 表示已獲取ngx_connection_t結構體的連接數; * ngx_stat_reading 表示正在接收TCP字符流的連接數; * ngx_stat_writing 表示正在發送TCP字符流的連接數; * ngx_stat_waiting 表示正在等待事件發生的連接數; */ size += cl /* ngx_stat_accepted */ + cl /* ngx_stat_handled */ + cl /* ngx_stat_requests */ + cl /* ngx_stat_active */ + cl /* ngx_stat_reading */ + cl /* ngx_stat_writing */ + cl; /* ngx_stat_waiting */ #endif /* 初始化共享內存信息 */ shm.size = size; shm.name.len = sizeof("nginx_shared_zone"); shm.name.data = (u_char *) "nginx_shared_zone"; shm.log = cycle->log; /* 創建共享內存 */ if (ngx_shm_alloc(&shm) != NGX_OK) { return NGX_ERROR; } /* 獲取共享內存的首地址 */ shared = shm.addr; ngx_accept_mutex_ptr = (ngx_atomic_t *) shared; /* -1表示以非阻塞模式獲取共享內存鎖 */ ngx_accept_mutex.spin = (ngx_uint_t) -1; if (ngx_shmtx_create(&ngx_accept_mutex, (ngx_shmtx_sh_t *) shared, cycle->lock_file.data) != NGX_OK) { return NGX_ERROR; } /* 初始化變量 */ ngx_connection_counter = (ngx_atomic_t *) (shared + 1 * cl); (void) ngx_atomic_cmp_set(ngx_connection_counter, 0, 1); ngx_log_debug2(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "counter: %p, %d", ngx_connection_counter, *ngx_connection_counter); ngx_temp_number = (ngx_atomic_t *) (shared + 2 * cl); tp = ngx_timeofday(); ngx_random_number = (tp->msec << 16) + ngx_pid; #if (NGX_STAT_STUB) ngx_stat_accepted = (ngx_atomic_t *) (shared + 3 * cl); ngx_stat_handled = (ngx_atomic_t *) (shared + 4 * cl); ngx_stat_requests = (ngx_atomic_t *) (shared + 5 * cl); ngx_stat_active = (ngx_atomic_t *) (shared + 6 * cl); ngx_stat_reading = (ngx_atomic_t *) (shared + 7 * cl); ngx_stat_writing = (ngx_atomic_t *) (shared + 8 * cl); ngx_stat_waiting = (ngx_atomic_t *) (shared + 9 * cl); #endif return NGX_OK; } ~~~ ? ? ? ngx_event_process_init 方法在文件[src/event/ngx_event.c](http://lxr.nginx.org/source/src/event/ngx_event.c) 中定義: ~~~ static ngx_int_t ngx_event_process_init(ngx_cycle_t *cycle) { ngx_uint_t m, i; ngx_event_t *rev, *wev; ngx_listening_t *ls; ngx_connection_t *c, *next, *old; ngx_core_conf_t *ccf; ngx_event_conf_t *ecf; ngx_event_module_t *module; /* 獲取ngx_core_module核心模塊的配置結構 */ ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module); /* 獲取ngx_event_core_module事件核心模塊的配置結構 */ ecf = ngx_event_get_conf(cycle->conf_ctx, ngx_event_core_module); /* * 在事件核心模塊啟用accept_mutex鎖的情況下, * 只有在master-worker工作模式并且worker進程數量大于1, * 此時,才確定進程啟用負載均衡鎖; */ if (ccf->master && ccf->worker_processes > 1 && ecf->accept_mutex) { ngx_use_accept_mutex = 1; ngx_accept_mutex_held = 0; ngx_accept_mutex_delay = ecf->accept_mutex_delay; } else {/* 否則關閉負載均衡鎖 */ ngx_use_accept_mutex = 0; } #if (NGX_WIN32) /* * disable accept mutex on win32 as it may cause deadlock if * grabbed by a process which can't accept connections */ ngx_use_accept_mutex = 0; #endif ngx_queue_init(&ngx_posted_accept_events); ngx_queue_init(&ngx_posted_events); /* 初始化由紅黑樹實現的定時器 */ if (ngx_event_timer_init(cycle->log) == NGX_ERROR) { return NGX_ERROR; } /* 根據use配置項所指定的事件模塊,調用ngx_actions_t中的init方法初始化事件模塊 */ for (m = 0; ngx_modules[m]; m++) { if (ngx_modules[m]->type != NGX_EVENT_MODULE) { continue; } if (ngx_modules[m]->ctx_index != ecf->use) { continue; } module = ngx_modules[m]->ctx; if (module->actions.init(cycle, ngx_timer_resolution) != NGX_OK) { /* fatal */ exit(2); } break; } #if !(NGX_WIN32) /* * NGX_USE_TIMER_EVENT只有在eventport和kqueue事件模型中使用, * 若配置文件nginx.conf設置了timer_resolution配置項, * 并且事件模型不為eventport和kqueue時,調用settimer方法, */ if (ngx_timer_resolution && !(ngx_event_flags & NGX_USE_TIMER_EVENT)) { struct sigaction sa; struct itimerval itv; ngx_memzero(&sa, sizeof(struct sigaction)); /* * ngx_timer_signal_handler的實現如下: * void ngx_timer_signal_handler(int signo) * { * ngx_event_timer_alarm = 1; * } * ngx_event_timer_alarm 為1時表示需要更新系統時間,即調用ngx_time_update方法; * 更新完系統時間之后,該變量設為0; */ /* 指定信號處理函數 */ sa.sa_handler = ngx_timer_signal_handler; /* 初始化信號集 */ sigemptyset(&sa.sa_mask); /* 捕獲信號SIGALRM */ if (sigaction(SIGALRM, &sa, NULL) == -1) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, "sigaction(SIGALRM) failed"); return NGX_ERROR; } /* 設置時間精度 */ itv.it_interval.tv_sec = ngx_timer_resolution / 1000; itv.it_interval.tv_usec = (ngx_timer_resolution % 1000) * 1000; itv.it_value.tv_sec = ngx_timer_resolution / 1000; itv.it_value.tv_usec = (ngx_timer_resolution % 1000 ) * 1000; /* 使用settimer函數發送信號 SIGALRM */ if (setitimer(ITIMER_REAL, &itv, NULL) == -1) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, "setitimer() failed"); } } /* 對poll、/dev/poll、rtsig事件模塊的特殊處理 */ if (ngx_event_flags & NGX_USE_FD_EVENT) { struct rlimit rlmt; if (getrlimit(RLIMIT_NOFILE, &rlmt) == -1) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, "getrlimit(RLIMIT_NOFILE) failed"); return NGX_ERROR; } cycle->files_n = (ngx_uint_t) rlmt.rlim_cur; cycle->files = ngx_calloc(sizeof(ngx_connection_t *) * cycle->files_n, cycle->log); if (cycle->files == NULL) { return NGX_ERROR; } } #endif /* 預分配連接池 */ cycle->connections = ngx_alloc(sizeof(ngx_connection_t) * cycle->connection_n, cycle->log); if (cycle->connections == NULL) { return NGX_ERROR; } c = cycle->connections; /* 預分配讀事件結構,讀事件個數與連接數相同 */ cycle->read_events = ngx_alloc(sizeof(ngx_event_t) * cycle->connection_n, cycle->log); if (cycle->read_events == NULL) { return NGX_ERROR; } rev = cycle->read_events; for (i = 0; i < cycle->connection_n; i++) { rev[i].closed = 1; rev[i].instance = 1; } /* 預分配寫事件結構,寫事件個數與連接數相同 */ cycle->write_events = ngx_alloc(sizeof(ngx_event_t) * cycle->connection_n, cycle->log); if (cycle->write_events == NULL) { return NGX_ERROR; } wev = cycle->write_events; for (i = 0; i < cycle->connection_n; i++) { wev[i].closed = 1; } i = cycle->connection_n; next = NULL; /* 按照序號,將讀、寫事件與連接對象對應,即設置到每個ngx_connection_t 對象中 */ do { i--; c[i].data = next; c[i].read = &cycle->read_events[i]; c[i].write = &cycle->write_events[i]; c[i].fd = (ngx_socket_t) -1; next = &c[i]; #if (NGX_THREADS) c[i].lock = 0; #endif } while (i); /* 設置空閑連接鏈表 */ cycle->free_connections = next; cycle->free_connection_n = cycle->connection_n; /* for each listening socket */ /* 為所有ngx_listening_t監聽對象中的connections成員分配連接,并設置讀事件的處理方法 */ ls = cycle->listening.elts; for (i = 0; i < cycle->listening.nelts; i++) { /* 為監聽套接字分配連接,并設置讀事件 */ c = ngx_get_connection(ls[i].fd, cycle->log); if (c == NULL) { return NGX_ERROR; } c->log = &ls[i].log; c->listening = &ls[i]; ls[i].connection = c; rev = c->read; rev->log = c->log; rev->accept = 1; #if (NGX_HAVE_DEFERRED_ACCEPT) rev->deferred_accept = ls[i].deferred_accept; #endif if (!(ngx_event_flags & NGX_USE_IOCP_EVENT)) { if (ls[i].previous) { /* * delete the old accept events that were bound to * the old cycle read events array */ old = ls[i].previous->connection; if (ngx_del_event(old->read, NGX_READ_EVENT, NGX_CLOSE_EVENT) == NGX_ERROR) { return NGX_ERROR; } old->fd = (ngx_socket_t) -1; } } #if (NGX_WIN32) if (ngx_event_flags & NGX_USE_IOCP_EVENT) { ngx_iocp_conf_t *iocpcf; rev->handler = ngx_event_acceptex; if (ngx_use_accept_mutex) { continue; } if (ngx_add_event(rev, 0, NGX_IOCP_ACCEPT) == NGX_ERROR) { return NGX_ERROR; } ls[i].log.handler = ngx_acceptex_log_error; iocpcf = ngx_event_get_conf(cycle->conf_ctx, ngx_iocp_module); if (ngx_event_post_acceptex(&ls[i], iocpcf->post_acceptex) == NGX_ERROR) { return NGX_ERROR; } } else { rev->handler = ngx_event_accept; if (ngx_use_accept_mutex) { continue; } if (ngx_add_event(rev, NGX_READ_EVENT, 0) == NGX_ERROR) { return NGX_ERROR; } } #else /* 為監聽端口的讀事件設置處理方法ngx_event_accept */ rev->handler = ngx_event_accept; if (ngx_use_accept_mutex) { continue; } if (ngx_event_flags & NGX_USE_RTSIG_EVENT) { if (ngx_add_conn(c) == NGX_ERROR) { return NGX_ERROR; } } else { /* 將監聽對象連接的讀事件添加到事件驅動模塊中 */ if (ngx_add_event(rev, NGX_READ_EVENT, 0) == NGX_ERROR) { return NGX_ERROR; } } #endif } return NGX_OK; } ~~~ 參考資料: 《深入理解 Nginx 》 《[nginx事件模塊分析(二)](http://blog.csdn.net/freeinfor/article/details/16343223)》
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看