Nginx服务器中的模块编写及相关内核源码初探
1.nginx模块
首先nginx和apache最大的不同就是nginx的模块不能够动态添加,需要在编译时,指定要添加的模块路径,与nginx源码一起编译。
nginx模块的处理流程:
a.客户端发送http请求到nginx服务器
b.nginx基于配置文件中的位置选择一个合适的处理模块
c.负载均衡模块选择一台后端服务器(反向代理情况下)
d.处理模块进行处理并把输出缓冲放到第一个过滤模块上
e.第一个过滤模块处理后输出给第二个过滤模块
f.然后第二个过滤模块又到第三个过滤模块
g.第N个过滤模块。。。
h.处理结果发给客户端
2.nginx模块编写
a、创建模块文件夹
mkdir-p/opt/nginx_hello_world cd/op/nginx_hello_word
b、创建模块配置文件
vi/opt/nginx_hello_word/config
c、创建模块主文件
vi/opt/nginx_hello_world/ngx_http_hello_world_module.c
写入如下内容:
#include<ngx_config.h> #include<ngx_core.h> #include<ngx_http.h> staticchar*ngx_http_hello_world(ngx_conf_t*cf,ngx_command_t*cmd,void*conf);
写的helloworld模块
/*Commands*/
staticngx_command_tngx_http_hello_world_commands[]={
{ngx_string("hello_world"),
NGX_HTTP_LOC_CONF|NGX_CONF_NOARGS,
ngx_http_hello_world,
0,
0,
NULL},
ngx_null_command
};
staticu_charngx_hello_world[]="helloworld";
staticngx_http_module_tngx_http_hello_world_module_ctx={
NULL,/*preconfiguration*/
NULL,/*postconfiguration*/
NULL,/*createmainconfiguration*/
NULL,/*initmainconfiguration*/
NULL,/*createserverconfiguration*/
NULL,/*mergeserverconfiguration*/
NULL,/*createlocationconfiguration*/
NULL/*mergelocationconfiguration*/
};
/*hook*/
ngx_module_tngx_http_hello_world_module={
NGX_MODULE_V1,
&ngx_http_hello_world_module_ctx,/*modulecontext*/
ngx_http_hello_world_commands,/*moduledirectives*/
NGX_HTTP_MODULE,/*moduletype*/
NULL,/*initmaster*/
NULL,/*initmodule*/
NULL,/*initprocess*/
NULL,/*initthread*/
NULL,/*exitthread*/
NULL,/*exitprocess*/
NULL,/*exitmaster*/
NGX_MODULE_V1_PADDING
};
staticngx_int_t
ngx_http_hello_world_handler(ngx_http_request_t*r)
{
ngx_int_trc;
ngx_buf_t*b;
ngx_chain_tout;
/*HttpOutputBuffer*/
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));
out.buf=b;
out.next=NULL;
b->pos=ngx_hello_world;
b->last=ngx_hello_world+sizeof(ngx_hello_world);
b->memory=1;
b->last_buf=1;
r->headers_out.status=NGX_HTTP_OK;
r->headers_out.content_length_n=sizeof(ngx_hello_world);
ngx_http_send_header(r);
returnngx_http_output_filter(r,&out);
}
staticchar*
ngx_http_hello_world(ngx_conf_t*cf,ngx_command_t*cmd,void*conf)
{
ngx_http_core_loc_conf_t*clcf;
/*registerhanlder*/
clcf=ngx_http_conf_get_module_loc_conf(cf,ngx_http_core_module);
clcf->handler=ngx_http_hello_world_handler;
returnNGX_CONF_OK;
}
d、下载nginx源码包,我下载的是nginx-1.0.13.tar.gz
这里注意在编译helloworld模块前首先确认,nginx是否可以独立编译成功,是否安装了所需的所有模块。
与helloworld模块一起编译nginx:
./configure--prefix=/usr/local/nginx--add-module=/opt/nginx_hello_world/ make makeinstall
e、配置nginx.conf
location=/hello{
hello_world;
}
f、启动nginx,访问http://localhost/hello,可以看到编写的helloworld模块输出的文字。
3.helloworld模块分析
a.ngx_command_t函数用于定义包含模块指令的静态数组ngx_http_hello_world_commands
staticngx_command_tngx_http_hello_world_commands[]={
{ngx_string("hello_world"),//设置指令名称字符串,注意不能包含空格,数据类型ngx_str_t之后会详细讲解。
NGX_HTTP_LOC_CONF|NGX_CONF_NOARGS,//配置指令的合法位置,这里表示:location部分合法,并且指令没有参数。
ngx_http_hello_world,//回调函数,三个参数(ngx_conf_t*cf,ngx_command_t*cmd,void*conf)
0,//后面的参数有待发掘,我还没有用到
0,
NULL},
ngx_null_command
};
b.staticu_charngx_hello_world[]="helloworld"则是输出到屏幕的字符串。
c.ngx_http_module_t用来定义结构体ngx_http_hello_world_module_ctx:
staticngx_http_module_tngx_http_hello_world_module_ctx={
NULL,/*读入配置前调用*/
NULL,/*读入配置后调用*/
NULL,/*创建全局部分配置时调用*/
NULL,/*初始化全局部分的配置时调用*/
NULL,/*创建虚拟主机部分的配置时调用*/
NULL,/*与全局部分配置合并时调用*/
NULL,/*创建位置部分的配置时调用*/
NULL/*与主机部分配置合并时调用*/
};
d.ngx_module_t定义结构体ngx_http_hello_world_module
ngx_module_tngx_http_hello_world_module={
NGX_MODULE_V1,
&ngx_http_hello_world_module_ctx,/*modulecontext*/
ngx_http_hello_world_commands,/*moduledirectives*/
NGX_HTTP_MODULE,/*moduletype*/
NULL,/*initmaster*/
NULL,/*initmodule*/
NULL,/*initprocess*/
NULL,/*initthread*/
NULL,/*exitthread*/
NULL,/*exitprocess*/
NULL,/*exitmaster*/
NGX_MODULE_V1_PADDING
};
e.处理函数,ngx_http_hello_world_handler,也是helloworld模块的核心部分。
staticngx_int_t
ngx_http_hello_world_handler(ngx_http_request_t*r)//ngx_http_request_t*r
//可以访问到客户端的头部和不久要发送的回复头部
{
ngx_int_trc;
ngx_buf_t*b;
ngx_chain_tout;
/*HttpOutputBuffer*/
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));
out.buf=b;
out.next=NULL;
b->pos=ngx_hello_world;
b->last=ngx_hello_world+sizeof(ngx_hello_world);
b->memory=1;
b->last_buf=1;
r->headers_out.status=NGX_HTTP_OK;
r->headers_out.content_length_n=sizeof(ngx_hello_world);
ngx_http_send_header(r);
returnngx_http_output_filter(r,&out);
}
helloworld模块里面涉及最重要的数据就是ngx_module_t指针数组,这个指针数组包含了当前编译版本支持的所有模块,这个指针数组定义实在自动脚本生成的objs/ngx_modules.c中,如下:
externngx_module_tngx_core_module;
externngx_module_tngx_errlog_module;
externngx_module_tngx_conf_module;
externngx_module_tngx_events_module;
externngx_module_tngx_event_core_module;
externngx_module_tngx_epoll_module;
externngx_module_tngx_http_module;
externngx_module_tngx_http_core_module;
externngx_module_tngx_http_log_module;
externngx_module_tngx_http_upstream_module;
externngx_module_tngx_http_static_module;
externngx_module_tngx_http_autoindex_module;
externngx_module_tngx_http_index_module;
externngx_module_tngx_http_auth_basic_module;
externngx_module_tngx_http_access_module;
externngx_module_tngx_http_limit_zone_module;
externngx_module_tngx_http_limit_req_module;
externngx_module_tngx_http_geo_module;
externngx_module_tngx_http_map_module;
externngx_module_tngx_http_split_clients_module;
externngx_module_tngx_http_referer_module;
externngx_module_tngx_http_rewrite_module;
externngx_module_tngx_http_proxy_module;
externngx_module_tngx_http_fastcgi_module;
externngx_module_tngx_http_uwsgi_module;
externngx_module_tngx_http_scgi_module;
externngx_module_tngx_http_memcached_module;
externngx_module_tngx_http_empty_gif_module;
externngx_module_tngx_http_browser_module;
externngx_module_tngx_http_upstream_ip_hash_module;
externngx_module_tngx_http_cache_purge_module;
externngx_module_tngx_http_write_filter_module;
externngx_module_tngx_http_header_filter_module;
externngx_module_tngx_http_chunked_filter_module;
externngx_module_tngx_http_range_header_filter_module;
externngx_module_tngx_http_gzip_filter_module;
externngx_module_tngx_http_postpone_filter_module;
externngx_module_tngx_http_ssi_filter_module;
externngx_module_tngx_http_charset_filter_module;
externngx_module_tngx_http_userid_filter_module;
externngx_module_tngx_http_headers_filter_module;
externngx_module_tngx_http_copy_filter_module;
externngx_module_tngx_http_range_body_filter_module;
externngx_module_tngx_http_not_modified_filter_module;
ngx_module_t*ngx_modules[]={
&ngx_core_module,
&ngx_errlog_module,
&ngx_conf_module,
&ngx_events_module,
&ngx_event_core_module,
&ngx_epoll_module,
&ngx_http_module,
&ngx_http_core_module,
&ngx_http_log_module,
&ngx_http_upstream_module,
&ngx_http_static_module,
&ngx_http_autoindex_module,
&ngx_http_index_module,
&ngx_http_auth_basic_module,
&ngx_http_access_module,
&ngx_http_limit_zone_module,
&ngx_http_limit_req_module,
&ngx_http_geo_module,
&ngx_http_map_module,
&ngx_http_split_clients_module,
&ngx_http_referer_module,
&ngx_http_rewrite_module,
&ngx_http_proxy_module,
&ngx_http_fastcgi_module,
&ngx_http_uwsgi_module,
&ngx_http_scgi_module,
&ngx_http_memcached_module,
&ngx_http_empty_gif_module,
&ngx_http_browser_module,
&ngx_http_upstream_ip_hash_module,
&ngx_http_cache_purge_module,
&ngx_http_write_filter_module,
&ngx_http_header_filter_module,
&ngx_http_chunked_filter_module,
&ngx_http_range_header_filter_module,
&ngx_http_gzip_filter_module,
&ngx_http_postpone_filter_module,
&ngx_http_ssi_filter_module,
&ngx_http_charset_filter_module,
&ngx_http_userid_filter_module,
&ngx_http_headers_filter_module,
&ngx_http_copy_filter_module,
&ngx_http_range_body_filter_module,
&ngx_http_not_modified_filter_module,
NULL
};
这里只有每个模块变量的声明,并且每个模块的定义都包含在自己的模块文件当中,比如ngx_core_module定义在src/core/nginx.c中:
ngx_module_tngx_core_module={
NGX_MODULE_V1,
&ngx_core_module_ctx,/*modulecontext*/
ngx_core_commands,/*moduledirectives*/
NGX_CORE_MODULE,/*moduletype*/
NULL,/*initmaster*/
NULL,/*initmodule*/
NULL,/*initprocess*/
NULL,/*initthread*/
NULL,/*exitthread*/
NULL,/*exitprocess*/
NULL,/*exitmaster*/
NGX_MODULE_V1_PADDING
};
是不是跟helloworld里面非常相似了,没错,他们都是模块,唯一的不同点就是helloworld是你另外加进去的。
到现在位置也只是初探nginx的模块,最后提一张别人画的nginx的模块图,有助于接下来的学习。