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

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

-

解剖Nginx·模块开发篇(3)ngx_http_hello_world_module 模块的基本函数实现的更多相关文章

  1. 解剖Nginx·模块开发篇(2)ngx_http_hello_world_module 模块基本结构定义

    elloWorld 是一个典型的 location 模块.什么是 location 模块?在 Nginx 中,根据作用域,有 main 模块.server 模块.location 模块. 1 模块定义 ...

  2. 解剖Nginx·模块开发篇(1)跑起你的 Hello World 模块!

    1 学习 Nginx 模块开发需要有哪些准备? 需要的预备知识不多,有如下几点: 有过一些 C 语言的编程经历: 知道 Nginx 是干嘛的,并有过编写或改写 Nginx 的配置文件的经历. OK,就 ...

  3. nginx模块开发篇 (阿里著作)

    背景介绍 nginx历史 使用简介 nginx特点介绍 nginx平台初探(100%) 初探nginx架构(100%) nginx基础概念(100%) connection request 基本数据结 ...

  4. 【Nginx】开发一个HTTP过滤模块

    与HTTP处理模块不同.HTTP过滤模块的工作是对发送给用户的HTTP响应做一些加工. server返回的一个响应能够被随意多个HTTP过滤模块以流水线的方式依次处理.HTTP响应分为头部和包体,ng ...

  5. 解剖Nginx·自动脚本篇(5)编译器相关主脚本

    在 Nginx 的自动脚本中,auto/cc目录下的所有脚本都是用于编译器相关配置使用的.Nginx的出色跨平台性(Linux.Darwin.Solaris.Win32 等)就有这些脚本的贡献.该目录 ...

  6. 解剖Nginx·模块开发篇(5)解读内置非默认模块 ngx_http_stub_status_module

    1 Background ngx_http_stub_status_module 是一个 Nginx 的内置 HTTP 模块,该模块可以提供 Nginx 的状态信息.默认情况下这个模块是不被编译进来的 ...

  7. 解剖Nginx·模块开发篇(4)模块开发中的命名规则和模块加载与运行流程

    1 命名规则 1.1 基本变量 基本变量有三个: ngx_module_t 类型的 ngx_http_foo_bar_module: ngx_command_t 类型的数组 ngx_http_foo_ ...

  8. Nginx模块开发1_明白自定义模块的编译流程

    自定义模块的编译流程 --add-module参数 configure使用--add-module参数指定添加模块目录. config脚本 由--add-module指定的目录保存为$ngx-addo ...

  9. 解剖Nginx·自动脚本篇(3)源码相关变量脚本 auto/sources

    在configure脚本中,运行完auto/options和auto/init脚本后,接下来就运行auto/soures脚本.这个脚本是为编译做准备的. 目录 核心模块 事件模块 OpenSSL 模块 ...

随机推荐

  1. JS实现动态提示框

    引言 什么项目都有个需求,应开发需求,需要写一个公式编辑器选择公式的插件,下面给大家讲一下实现过程.(擦汗,强作淡定,咳,开嗓~) 看图说话 本小菜开发功能前乐于先写个需求思维导图(纯属个人爱好): ...

  2. jenkins忘记密码如何处理?

    一.admin密码未更改情况 1.进入\Jenkins\secrets目录,打开initialAdminPassword文件,复制密码: 2.访问Jenkins页面,输入管理员admin,及刚才的密码 ...

  3. BZOJ1590:[Usaco2008 Dec]Secret Message秘密信息

    浅谈\(Trie\):https://www.cnblogs.com/AKMer/p/10444829.html 题目传送门:https://lydsy.com/JudgeOnline/problem ...

  4. ASP.NET比较常用的26个性能优化技巧

    1. 数据库访问性能优化 数据库的连接和关闭 访问数据库资源需要创建连接.打开连接和关闭连接几个操作.这些过程需要多次与数据库交换信息以通过身份验证,比较耗费服务器资源.ASP.NET中提供了连接池( ...

  5. Jenkins的pipeline

    说明 再官网文档上有说明pipeline的工作流程,具体可以参考pipeline文档和语法文档. 这里将pipeline的生命周期图贴出来  我们暂时不会用到完整的流程,只摘取有用的部分,完成最小的流 ...

  6. 关于INTEL FPGA设计工具DSP Builder

    一段时间以来,MathWorks一直主张使用Matlab和Simulink开发工具进行基于模型的设计,因为好的设计技术使您能够在更短的时间内开发更高质量的复杂软件.基于模块的设计采用了数学和可视化的方 ...

  7. SpringMVC中注解控制器及数据绑定

    一.Spring2.5之前,我们都是通过实现Controller接口或其他实现来定义我们的处理器类. 二.Spring2.5引入注解式处理器支持,通过@Controller 和 @RequestMap ...

  8. 如何通过.Net Compact Framework来获得应用程序的当前路径

    在Win CE上是没有驱动器的概念的,所以要想使用System.IO.Directory.GetCurrentDirectory()来获得当前路径的话,在CF中会遇到未知错误.   应该使用Path. ...

  9. mysql连接慢,修改配置文件

    修改配置 port= skip-locking skip-name-resolve

  10. React组件间信息传递方式

    组件之间传递信息方式,总体可分为以下5种: 1.(父组件)向(子组件)传递信息 2.(父组件)向更深层的(子组件) 进行传递信息  >>利用(context) 3.(子组件)向(父组件)传 ...