模块调用原理
先来看看nginx是如何调用模块的,以http模块为例,从书中截了一张图:
大致流程是:worker进程在一个循环语句中调用事件模块检测网络事件,当检测到有客户端发起请求连接时,建立连接并根据配置文件交给http框架处理,接受到完整的http头部后交给具体的http处理模块处理。
模块调用方式
- 典型调用:http框架接受到http请求的头部后,将请求的URL与配置文件中的所有location进行匹配,匹配后再根据location{}内的配置项选择http模块来调用。并且是只有配置了location /uri{mytest;}后,http框架才会在某个请求匹配了/uri后调用它处理请求。如果某个匹配了URI请求的location中没有配置mytest配置项,mytest模块依然不会被调用。
- 非典型调用:例如ngx_http_access_module模块,任何http模块都会调用ngx_http_access_module模块处理,只是该模块会根据它感兴趣的的配置项及所在的配置块来决定行为方式。
模块添加步骤
假设我们要编写并添加一个mytest模块,需要以下步骤:
- 编写config文件:
ngx_addon_name=ngx_http_mytest_module
HTTP_MODULES="$HTTP_MODULES ngx_http_mytest_module"
NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/ngx_http_mytest_module.c"
-
编写ngx_http_mytest_module.c文件:
可先暂时参考link的代码,访问网页时显示hello world -
修改nginx.conf配置文件:
添加对应模块的location块
location /test{
mytest;
}
- 编译安装
首先要用如下指令查看以前的配置参数
/usr/local/nginx/sbin/nginx -V
因为是第一次装新模块,所以为空
然后进入nginx的源码目录,执行
注意如果原来的配置参数不为空,要先加上原来的配置参数。加入的模块目录httpmodule下应该有两个文件,就是第1,2步中的config和ngx_http_mytest_module.c。
make完成后不要make install,否则就是覆盖安装了,直接nginx -s stop 再nginx启动就行。测试一下页面
成功。
模块具体分析
(1)一些数据结构的封装
- 整形
typedef intptr_t ngx_int_t; //有符号整形
typedef uintptr_t ngx_uint_t; //无符号整形
- 字符串
typedef struct {
size_t len; //字符串有效长度
u_char *data; //字符串起始地址
} ngx_str_t;
- 链表容器
注意每一个链表元素ngx_list_part_t是一个数组,有连续的内存。
typedef struct ngx_list_part_s ngx_list_part_t; //描述链表的一个元素
struct ngx_list_part_s {
void *elts; //数组起始地址
ngx_uint_t nelts; //数组已经使用了多少个元素
ngx_list_part_t *next; //下一个链表元素的地址
};
typedef struct {
ngx_list_part_t *last; //链表首个数组元素
ngx_list_part_t part; //链表最后一个数组元素
size_t size; //每一个数组元素占用空间大小
ngx_unint_t nalloc; //数组的容量,即最多能存多少的数据
ngx_pool_t *pool; //管理内存分配的内存池对象
} ngx_list_t; //描述整个链表
内存分布如图所示: