ホームページ  >  記事  >  バックエンド開発  >  helloモジュールの作成

helloモジュールの作成

WBOY
WBOYオリジナル
2016-08-08 09:24:061150ブラウズ

高性能な同時実行サーバーを学ぶために、Nginx の実装を勉強する予定です。慣例に従って、最初に hello world プログラムを作成する必要があるため、次のステップでは、Nginx フレームワークで「Hello World」を出力する簡単な HTTP モジュールを作成する方法を紹介します。

Hello 設定項目の処理を定義する

まず、モジュールの設定ファイルのパラメータを定義するコマンド配列を定義する必要があります。各配列要素は ngx_command_t 型で、配列の終わりは ngx_null_command で終了します。

Nginx は、構成ファイル内の構成項目を解析するときに、まずすべてのモジュールをスキャンし、モジュールごとにコマンド配列をスキャンします。各 ngx_command_t 構造体は、対象となる構成項目を定義します。構造は次のように定義されています:

<code><span>struct</span> ngx_command_s {
    <span>/* 配置项名称 */</span>
    ngx_str_t             name;
    <span>/* 指定配置项可以出现的位置 */</span>
    ngx_uint_t            type;
    <span>/* 出现了name中指定的配置项后,将会调用set方法处理配置项的参数 */</span><span>char</span>               *(*<span>set</span>)(ngx_conf_t *cf, ngx_command_t *cmd, <span>void</span> *conf);
    ngx_uint_t            conf;
    <span>/* 在配置文件中的偏移量 */</span>
    ngx_uint_t            offset;
    <span>/* 配置项读取后的处理过程,必须是ngx_conf_post_t结构的指针 */</span><span>void</span>                 *post;
};

<span>#define ngx_null_command  { ngx_null_string, 0, NULL, 0, 0, NULL }</span></code>

コマンド配列を理解した後、hello 設定項目の処理を定義します:

<code><span>static</span> ngx_command_t ngx_http_hello_commands[] = {

    {   ngx_string(<span>"hello"</span>),
        NGX_HTTP_LOC_CONF|NGX_CONF_NOARGS,
        ngx_http_hello,
        NGX_HTTP_LOC_CONF_OFFSET,
        <span>0</span>,
        NULL },

    ngx_null_command
};</code>

このうち、ngx_http_hello は、hello 設定項目が ngx_command_t 構造体に出現するときのセット メンバーです。特定の構成ブロックでは、Nginx は ngx_http_hello メソッドを呼び出します。以下は ngx_http_hello の実装です:

<code><span>static</span><span>char</span> *
ngx_http_hello(ngx_conf_t *cf, ngx_command_t *cmd, <span>void</span> *conf)
{
    ngx_http_core_loc_conf_t *clcf;

    <span>/* 首先找到hello配置项所属的配置块 */</span>
    clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);

    <span>/* HTTP框架在处理用户请求进行到NGX_HTTP_CONTENT_PHASE阶段时
     * 如果请求的主机域名、URI与hello配置项所在的配置块相匹配
     * 则调用ngx_http_hello_handler方法处理这个请求
     */</span>
    clcf->handler = ngx_http_hello_handler;

    <span>return</span> NGX_CONF_OK;
}</code>

hello モジュールを定義します

HTTP モジュールを定義する方法は非常に簡単です。次のように ngx_moodule_t 構造体を定義するだけです:

<code>ngx_module_t ngx_http_hello_module = {
    NGX_MODULE_V1,
    &ngx_http_hello_module_ctx,    <span>/* module context */</span>
    ngx_http_hello_commands,       <span>/* module directives */</span>
    NGX_HTTP_MODULE,               <span>/* module type */</span>
    NULL,                          <span>/* init master */</span>
    NULL,                          <span>/* init module */</span>
    NULL,                          <span>/* init process */</span>
    NULL,                          <span>/* init thread */</span>
    NULL,                          <span>/* exit thread */</span>
    NULL,                          <span>/* exit process */</span>
    NULL,                          <span>/* exit master */</span>
    NGX_MODULE_V1_PADDING
};</code>

hello モジュールはコンパイル時に ngx_modules グローバルに追加されます配列内の時間。

このうち、ngx_http_hello_commands は、前のセクションで定義した hello 設定項目の処理です。 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模块不需要做什么工作,所以定义如下:

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

处理用户请求

最后就是处理用户请求了,这里需要一点HTTP的知识,可以参考HTTP协议入门。我们是通过实现ngx_http_hello_handler方法来处理用户的请求了,该方法定义如下:

<code><span>static</span> ngx_int_t
ngx_http_hello_handler(ngx_http_request_t *r)</code>

其中ngx_http_request_t结构体中包含了请求的所有信息(如方法,URI,协议版本号和头部等),除此之外,还包含了其他很多成员,例如内存池,响应报头等等。

因为我们只处理GET方法和HEAD方法,所以需要做如下判断:

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

接下来因为我们不需要请求中的包体,所以需要丢弃掉包体,方法如下:

<code>ngx_int_t rc = ngx_http_discard_request_body(r);
<span>if</span> (rc != NGX_OK) {
    <span>return</span> rc;
}</code>

然后是设置返回的响应包,返回的包体只包含一个”Hello World”字符串:

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

最后就是发送响应包的包头和包体了:

<code>    rc = ngx_http_send_header(r);
    <span>if</span> (rc == NGX_ERR || rc > NGX_OK || r->header_only) {
        <span>return</span> rc;
    }

    ngx_buf_t *b;
    b = ngx_create_temp_buf(r->pool, response.len);
    <span>if</span> (b == NULL) {
        <span>return</span> NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    ngx_memcpy(b->pos, response.data, response.len);
    b->last = b->pos + response.len;
    b->last_buf = <span>1</span>;

    ngx_chain_t out;
    out.buf = b;
    out.next = NULL;

    <span>/* send the buffer chain of your response */</span><span>return</span> ngx_http_output_filter(r, &out);</code>

完整代码可以在这里查看:hello_module

编译和运行

在代码同目录下新建一个config文件,添加这样几行:

<code>ngx_addon_name=ngx_http_hello_module
HTTP_MODULES=<span>"<span>$HTTP_MODULES</span> ngx_http_hello_module"</span>
NGX_ADDON_SRCS=<span>"<span>$NGX_ADDON_SRCS</span><span>$ngx_addon_dir</span>/ngx_http_hello_module.c"</span></code>

然后进入Nginx的源码根目录,运行configure,记得带上–add-module参数,在参数后面接上我们自己编写的HTTP模块代码所在的路径:

<code>./configure --prefix=<span>/usr/local</span><span>/nginx --add-module=/code</span><span>/nginx-1.8.0/src</span><span>/http/hello</span>_module</code>

configure运行完成后,用make命令来编译,编译成功后输入make install完成安装。

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

<code>http{
    <span>...</span>
    server {
        <span>...</span>
        location /hello {
            hello;
        }
        <span>...</span>
    }
    <span>...</span>
}</code>

运行Nginx,然后在浏览器输入IP/hello
HTTP モジュールを定義しているため、typeNGX_HTTP_MODULE に設定する必要があります。

重要なメンバー void* ctx もあります。HTTP モジュールの場合、ctx ポインターは ngx_http_module_t インターフェイスを指す必要があります。

HTTP フレームワークは、設定ファイルの読み取りと再ロード時に ngx_http_module_t インターフェイスで記述された 8 つのステージを定義します。HTTP フレームワークが開始されると、各ステージで ngx_http_module_t の対応するメソッドが呼び出されます。作業が必要ない場合は、NULL として定義できます。 hello モジュールは何も行う必要がないため、次のように定義されます:

rrreee

ユーザー リクエストの処理

最後のステップでは、HTTP の概要を参照してください。 HTTP プロトコル。 ngx_http_hello_handler メソッドを実装することでユーザー リクエストを処理します。このメソッドは次のように定義されています:

rrreee

ngx_http_request_t 構造には、リクエストされたすべての情報 (メソッド、URI、プロトコルなど) が含まれています。バージョン番号やヘッダーなど)に加えて、メモリ プール、応答ヘッダーなど、他の多くのメンバーも含まれています。

🎜ここでは GET メソッドと HEAD メソッドのみを扱うため、次の判断を行う必要があります: 🎜rrreee🎜 次に、リクエストにパッケージ本体が必要ないため、パッケージ本体を破棄する必要があります。メソッドは次のとおりです: 🎜rrreee🎜次に、返された応答パッケージを設定します。返されたパッケージの本文には、「Hello World」文字列のみが含まれます: 🎜rrreee🎜 最後に、応答パッケージのヘッダーと本文が送信されます: 🎜rrreee🎜完全なコードここで参照できます: hello_module🎜🎜コンパイルして実行🎜🎜 コードと同じディレクトリに新しい config ファイルを作成し、次の行を追加します: 🎜rrreee🎜 次に、Nginx ソース コードのルート ディレクトリを入力します。 configure を実行します。–add-module パラメーターを忘れずに指定し、パラメーターの後に自分で作成した HTTP モジュール コードのパスを指定します: 🎜rrreee🎜configure が完了したら、make コマンドでコンパイルが成功したら、<code>make install code> と入力してインストールを完了します。 🎜🎜 <code>/usr/local/nginx/conf/nginx.conf を変更し、次の内容を追加します: 🎜rrreee🎜Nginx を実行し、ブラウザに IP/hello と入力して、 「Hello World文字列」が表示されます。 🎜🎜🎜🎜参考🎜🎜「Nginxを深く理解する」🎜🎜 🎜 以上、hello モジュールの書き方をさまざまな側面を含めて紹介しましたが、PHP チュートリアルに興味のある友人の参考になれば幸いです。 🎜 🎜 🎜
声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。