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的模块图,有助于接下来的学习。