设为首页 收藏本站
查看: 614|回复: 0

[经验分享] 解剖Nginx·模块开发篇(3)ngx_http_hello_world_module 模块的基本函数实现

[复制链接]

尚未签到

发表于 2015-11-13 14:00:40 | 显示全部楼层 |阅读模式
解剖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
-
   
版权声明:本文为博主原创文章,未经博主允许不得转载。合作请联系微信 sinosuperman。

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-138836-1-1.html 上篇帖子: Reverse Proxy Web Sockets with Nginx and Socket.IO 下篇帖子: Nginx事件处理中的connection和read、write事件的关联
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表