解剖Nginx·模組開發篇(3)ngx_http_hello_world_module 模組的基本函式實現
解剖Nginx·模組開發篇(3)ngx_http_hello_world_module 模組的基本函式實現
- 作者:柳大·Poechant(鍾超)
- 郵箱:zhongchao.ustc#gmail.com(# -> @)
- 部落格:Blog.CSDN.net/Poechant
- 日期:June 2nd, 2012
還記得我們定義過一個結構體如下嗎?
typedef struct {
ngx_str_t output_words;
} ngx_http_hello_world_loc_conf_t;
它就是 HelloWorld 的 location 元件配置,其中有一個字串成員 output_words。
1 create location
用於 ngx_http_hello_world_module_ctx 中的 location 建立函式:
static void* ngx_http_hello_world_create_loc_conf(ngx_conf_t* cf) {
ngx_http_hello_world_loc_conf_t* conf;
conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_hello_world_loc_conf_t));
if (conf == NULL) {
return NGX_CONF_ERROR;
}
conf->output_words.len = 0;
conf->output_words.data = NULL;
return conf;
}
我們可以看到,就是先分配一段 ngx_http_hello_world_loc_conf_t 所使用的大小的記憶體。並初始化 ngx_http_hello_world_loc_conf_t 唯一的成員 output_words。
2 merge location
用於 ngx_http_hello_world_module_ctx 中的 location 合併函式:
static char* ngx_http_hello_world_merge_loc_conf(ngx_conf_t* cf,
void* parent,
void* child) {
ngx_http_hello_world_loc_conf_t* prev = parent;
ngx_http_hello_world_loc_conf_t* conf = child;
ngx_conf_merge_str_value(conf->output_words, prev->output_words, "boy");
return NGX_CONF_OK;
}
3 ngx_http_hello_world
3.1 ngx_http_conf_get_module_loc_conf
首先你要了解一個 Nginx 提供的一個“函式”:
ngx_http_conf_get_module_loc_conf(
cf, // configuration
module
);
實際上它是一個巨集定義,在 ngx_http_config.h 中:
#define ngx_http_conf_get_module_loc_conf(cf, module) \
((ngx_http_conf_ctx_t *) cf->ctx)->loc_conf[module.ctx_index]
它的作用是通過 cf 配置的上下文,找到指定的 module 中的 location configuration。
3.2 ngx_http_hello_world
用於 ngx_http_hello_world_commands 中我們定義的唯一的一個命令的 set 欄位。
static char* ngx_http_hello_world(ngx_conf_t* cf,
ngx_command_t* cmd,
void* conf) {
ngx_http_core_loc_conf_t* clcf;
clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);
clcf->handler = ngx_http_hello_world_handler;
ngx_conf_set_str_slot(cf, cmd, conf);
return NGX_CONF_OK;
}
這個函式的作用,就是生成對請求的響應內容,即本例中的hello_world, Poechant
。然後獲取到 http_core_module 的 location configuration,即 clcf(Core Location ConF)。給 clcf 的 handler 欄位賦值 ngx_http_hello_world_handler,這個函式下面會介紹。然後再常規地呼叫 ngx_conf_set_str_slot。
4 ngx_http_hello_world_handler
首先你要再瞭解一個 Nginx 提供的一個“函式”:
4.1 ngx_http_conf_get_module_loc_conf
ngx_http_conf_get_module_loc_conf(
r, // request
module
);
實際上它是一個巨集定義,在 ngx_http_config.h 中:
#define ngx_http_get_module_loc_conf(r, module) (r)->loc_conf[module.ctx_index]
其作用是根據 module 的索引欄位(ctx_index),找到 request 所請求的 location 配置。
4.2 ngx_http_hello_world_handler
首先來看看 Nginx 中比較經典的緩衝區 ngx_buf_t 吧。這裡只介紹與本文相關的部分。
struct ngx_buf_s {
u_char *pos;
u_char *last;
u_char *start; /* start of buffer */
u_char *end; /* end of buffer */
…
};
這四個指標把緩衝區劃分為 3 個部分。分別如下:
- 第一部分(start 到 pos):
- 只讀緩衝區:對於只讀緩衝區,這部分是已讀部分;
- 只寫緩衝區:對於只寫緩衝區,不會有這部分。
- 第二部分(pos 到 last):
- 只讀緩衝區:對於只讀緩衝區,這部分是欲讀取的部分;
- 只寫緩衝區:對於只寫緩衝區,已寫入的區域。
- 第三部分(last 到 end):
- 只讀緩衝區:對於只讀緩衝區,不會有這部分;
- 只寫緩衝區:對於只寫緩衝區,剩餘可寫區域。
ngx_buf_t 之所以經典的另一個原因,是因為nginx可以提前flush輸出,所以這些buf被輸出後就可以重複使用,可以避免重分配,提高系統效能,被稱為free_buf,而沒有被輸出的buf就是busy_buf。
那麼來看 ngx_http_hello_world_handler 吧:
static ngx_int_t ngx_http_hello_world_handler(ngx_http_request_t* r) {
ngx_int_t rc;
ngx_buf_t* b;
ngx_chain_t out[2];
ngx_http_hello_world_loc_conf_t* hlcf;
hlcf = ngx_http_get_module_loc_conf(r, ngx_http_hello_world_module);
// 設定 request 的 header
r->headers_out.content_type.len = sizeof("text/plain") - 1;
r->headers_out.content_type.data = (u_char*)"text/plain";
// 分配緩衝區的記憶體空間
b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t));
// 第 1 塊緩衝區
out[0].buf = b;
out[0].next = &out[1];
// 本模組中,緩衝區只需要寫入資料,所以只設定 pos 和 last
b->pos = (u_char*)"hello_world, ";
b->last = b->pos + sizeof("hello_world, ") - 1;
b->memory = 1; // 標示緩衝區是記憶體緩衝
// 分配緩衝區的記憶體空間
b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t));
// 第 2 塊緩衝區
out[1].buf = b;
out[1].next = NULL;
// 本模組中,緩衝區只需要寫入資料,所以只設定 pos 和 last
b->pos = hlcf->output_words.data;
b->last = hlcf->output_words.data + (hlcf->output_words.len);
b->memory = 1; // 標示緩衝區是記憶體緩衝
b->last_buf = 1; // 標示整個響應最後一個緩衝區,nginx會立即傳送緩衝的所有資料
// 設定 request 的 header
r->headers_out.status = NGX_HTTP_OK;
r->headers_out.content_length_n = hlcf->output_words.len + sizeof("hello_world, ") - 1;
// 傳送 request
rc = ngx_http_send_header(r);
if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) {
return rc;
}
return ngx_http_output_filter(r, &out[0]);
}
5 Reference
- www.evanmiller.org/nginx-modules-guide.html
- http://blog.sina.com.cn/s/blog_7303a1dc0100x70t.html
-
轉載請註明來自柳大的CSDN部落格:Blog.CSDN.net/Poechant
-
相關文章
- 解剖Nginx·模組開發篇(2)ngx_http_hello_world_module 模組基本結構定義NginxHTTP
- 解剖Nginx·模組開發篇(1)跑起你的 Hello World 模組!Nginx
- 解剖Nginx·模組開發篇(4)模組開發中的命名規則和模組載入與執行流程Nginx
- 解剖Nginx·模組開發篇(6)配置檔案config入門Nginx
- 解剖Nginx·模組開發篇(5)解讀內建非預設模組 ngx_http_stub_status_moduleNginxHTTP
- nginx模組開發Nginx
- 全網開發網站搭建教程篇之Python 用函式實現模組化程式設計網站Python函式程式設計
- Nginx使用Lua模組實現WAFNginx
- Laravel-Module 模組開發一:評論模組實現Laravel
- 用函式實現模組化程式設計一函式程式設計
- 用函式實現模組化程式設計二函式程式設計
- 用函式實現模組化程式設計三函式程式設計
- FFmpeg開發筆記(四十)Nginx整合rtmp模組實現RTMP推拉流筆記Nginx
- socket模組函式函式
- 利用nginx的stream模組實現內網埠的轉發代理Nginx內網
- nginx事件模組 -- 第二篇Nginx事件
- nginx事件模組-- 第四篇Nginx事件
- nginx事件模組 -- 第三篇Nginx事件
- Nginx的Uwsgi模組(部分模組指令)Nginx
- No.7、函式模組函式
- R/3 基本模組的劃分: (轉)
- nginx事件模組 -- 第一篇Nginx事件
- Nginx常用的模組Nginx
- Nginx的Uwsgi模組Nginx
- Python 函式和模組Python函式
- Lua封裝函式模組並由其他模組呼叫封裝函式
- 模組的基本操作
- NGINX模組(一)Nginx
- NGINX模組(二)Nginx
- 從零手寫實現 nginx-21-modules 模組Nginx
- Nginx limit模組限制併發數NginxMIT
- Xposed模組的開發
- Linux上Nginx中開啟SSL模組,實現Https訪問LinuxNginxHTTP
- 一篇文章說透Nginx的rewrite模組Nginx
- Python(2):建立函式模組Python函式
- 函式模組:F4_DATE函式
- python檢視模組下的函式Python函式
- 開篇 | 模組化與解耦式開發在螞蟻金服 mPaaS 深度實踐探討解耦