hello模組的編寫

來源:互聯網
上載者:User
為了學習高效能並發伺服器,打算研究一下Nginx的實現。按照慣例,最開始都要寫一個hello world的程式,所以接下來就是介紹如何在Nginx的架構下編寫一個簡單的HTTP模組來列印”Hello World“。

定義hello配置項的處理

首先,我們需要定義一個commands數組用來定義模組的設定檔參數。每一個數組元素都是ngx_command_t類型,數組的結尾用ngx_null_command結尾。

Nginx在解析設定檔中的一個配置項時首先會遍曆所有的模組,對於每個模組而言,即通過遍曆commands數組進行。每一個ngx_command_t結構體定義了自己感興趣的一個配置項。該結構定義如下:

struct ngx_command_s {    /* 配置項名稱 */    ngx_str_t             name;    /* 指定配置項可以出現的位置 */    ngx_uint_t            type;    /* 出現了name中指定的配置項後,將會調用set方法處理配置項的參數 */char               *(*set)(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);    ngx_uint_t            conf;    /* 在設定檔中的位移量 */    ngx_uint_t            offset;    /* 配置項讀取後的處理過程,必須是ngx_conf_post_t結構的指標 */void                 *post;};#define ngx_null_command  { ngx_null_string, 0, NULL, 0, 0, NULL }

瞭解了commands數組後,我們定義hello配置項的處理:

static ngx_command_t ngx_http_hello_commands[] = {    {   ngx_string("hello"),        NGX_HTTP_LOC_CONF|NGX_CONF_NOARGS,        ngx_http_hello,        NGX_HTTP_LOC_CONF_OFFSET,        0,        NULL },    ngx_null_command};

其中,ngx_http_hello是ngx_command_t結構體中的set成員,當在某個配置塊中出現hello配置項時,Nginx會調用ngx_http_hello方法。下面是ngx_http_hello的實現:

staticchar *ngx_http_hello(ngx_conf_t *cf, ngx_command_t *cmd, void *conf){    ngx_http_core_loc_conf_t *clcf;    /* 首先找到hello配置項所屬的配置塊 */    clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);    /* HTTP架構在處理使用者請求進行到NGX_HTTP_CONTENT_PHASE階段時     * 如果請求的主機網域名稱、URI與hello配置項所在的配置塊相匹配     * 則調用ngx_http_hello_handler方法處理這個請求     */    clcf->handler = ngx_http_hello_handler;    return NGX_CONF_OK;}

定義hello模組

定義一個HTTP模組的方式很簡單,只要像下面這樣定義一個ngx_moodule_t的結構體:

ngx_module_t ngx_http_hello_module = {    NGX_MODULE_V1,    &ngx_http_hello_module_ctx,    /* module context */    ngx_http_hello_commands,       /* module directives */    NGX_HTTP_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};

則hello模組在編譯時間將會被加入到ngx_modules全域數組中。

其中ngx_http_hello_commands就是前一節我們定義的hello配置項的處理。

因為我們定義的是HTTP模組,所以type要設定成NGX_HTTP_MODULE

還有一個重要的成員void* ctx,對於HTTP模組來說,ctx指標必須指向ngx_http_module_t介面。

HTTP架構在讀取、重載設定檔時定義了由ngx_http_module_t介面描述的8個階段,HTTP架構在啟動的時候會在每個階段中調用ngx_http_module_t中相應的方法。如果不需要做什麼工作,則可以定義為NULL。因為hello模組不需要做什麼工作,所以定義如下:

static ngx_http_module_t ngx_http_hello_module_ctx = {    NULL,                          /* preconfiguration */    NULL,                           /* postconfiguration */    NULL,                          /* create main configuration */    NULL,                          /* init main configuration */    NULL,                          /* create server configuration */    NULL,                          /* merge server configuration */    NULL,                           /* create location configuration */    NULL                            /* merge location configuration */};

處理使用者請求

最後就是處理使用者請求了,這裡需要一點HTTP的知識,可以參考HTTP協議入門。我們是通過實現ngx_http_hello_handler方法來處理使用者的請求了,該方法定義如下:

static ngx_int_tngx_http_hello_handler(ngx_http_request_t *r)

其中ngx_http_request_t結構體中包含了請求的所有資訊(如方法,URI,協議版本號碼和頭部等),除此之外,還包含了其他很多成員,例如記憶體池,響應前序等等。

因為我們只處理GET方法和HEAD方法,所以需要做如下判斷:

if (!(r->method & (NGX_HTTP_GET | NGX_HTTP_HEAD))) {        return NGX_HTTP_NOT_ALLOWED; }

接下來因為我們不需要請求中的包體,所以需要丟棄掉包體,方法如下:

ngx_int_t rc = ngx_http_discard_request_body(r);if (rc != NGX_OK) {    return rc;}

然後是設定返回的響應包,返回的包體只包含一個”Hello World”字串:

ngx_str_type = ngx_string("text/plain");ngx_str_response = ngx_string("Hello World");r->headers_out.status = NGX_HTTP_OK;r->headers_out.content_length_n = response.len;r->headers_out.content_type = type;

最後就是發送響應包的包頭和包體了:

    rc = ngx_http_send_header(r);    if (rc == NGX_ERR || rc > NGX_OK || r->header_only) {        return rc;    }    ngx_buf_t *b;    b = ngx_create_temp_buf(r->pool, response.len);    if (b == NULL) {        return NGX_HTTP_INTERNAL_SERVER_ERROR;    }    ngx_memcpy(b->pos, response.data, response.len);    b->last = b->pos + response.len;    b->last_buf = 1;    ngx_chain_t out;    out.buf = b;    out.next = NULL;    /* send the buffer chain of your response */return ngx_http_output_filter(r, &out);

完整代碼可以在這裡查看:hello_module

編譯和運行

在代碼同目錄下建立一個config檔案,添加這樣幾行:

ngx_addon_name=ngx_http_hello_moduleHTTP_MODULES="$HTTP_MODULES ngx_http_hello_module"NGX_ADDON_SRCS="$NGX_ADDON_SRCS$ngx_addon_dir/ngx_http_hello_module.c"

然後進入Nginx的源碼根目錄,運行configure,記得帶上–add-module參數,在參數後面接上我們自己編寫的HTTP模組代碼所在的路徑:

./configure --prefix=/usr/local/nginx --add-module=/code/nginx-1.8.0/src/http/hello_module

configure運行完成後,用make命令來編譯,編譯成功後輸入make install完成安裝。

修改/usr/local/nginx/conf/nginx.conf,添加:

http{    ...    server {        ...        location /hello {            hello;        }        ...    }    ...}

運行Nginx,然後在瀏覽器輸入IP/hello就可以看到顯示的”Hello World字串了“。

參考

《深入理解Nginx》

以上就介紹了 hello模組的編寫,包括了方面的內容,希望對PHP教程有興趣的朋友有所協助。

  • 聯繫我們

    該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

    如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

    A Free Trial That Lets You Build Big!

    Start building with 50+ products and up to 12 months usage for Elastic Compute Service

    • Sales Support

      1 on 1 presale consultation

    • After-Sales Support

      24/7 Technical Support 6 Free Tickets per Quarter Faster Response

    • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.