zoukankan      html  css  js  c++  java
  • 解剖Nginx·模块开发篇(3)ngx_http_hello_world_module 模块的基本函数实现

    还记得我们定义过一个结构体如下吗?

    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

    1. www.evanmiller.org/nginx-modules-guide.html
    2. http://blog.sina.com.cn/s/blog_7303a1dc0100x70t.html

    -

  • 相关阅读:
    Python-Collections模块之defaultdict
    Python-Collections模块之deque
    Python-Collections模块之NameTuple
    Python-Collections模块之OrderedDict
    @常见的远程服务器连接工具:Xshell与secureCRT的比较!!!(对于刚接触的测试小白很有帮助哦)
    告诉你:传统测试和敏捷测试的区别!!!(比较全的解答,一看便明白)
    @软件测试环境搭建的详细流程(初学者不要错过哦,很实用)!!!!
    Netlib文件转化为mps文件
    新设备关联Gitlab
    CMake与OpenMP
  • 原文地址:https://www.cnblogs.com/breg/p/4043653.html
Copyright © 2011-2022 走看看