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> 

static char *ngx_http_hello_world(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);

写的helloworld模块

/* Commands */
static ngx_command_t ngx_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
}; 

static u_char ngx_hello_world[] = "hello world"; 

static ngx_http_module_t ngx_http_hello_world_module_ctx = {
 NULL,         /* preconfiguration */
 NULL,          /* postconfiguration */
 NULL,         /* create main configuration */
 NULL,         /* init main configuration */
 NULL,         /* create server configuration */
 NULL,         /* merge server configuration */
 NULL,         /* create location configuration */
 NULL         /* merge location configuration */
};
/* hook */
ngx_module_t ngx_http_hello_world_module = {
 NGX_MODULE_V1,
 &ngx_http_hello_world_module_ctx,    /* module context */
 ngx_http_hello_world_commands,     /* module directives */
 NGX_HTTP_MODULE,      /* module type */
 NULL,         /* init master */
 NULL,         /* init module */
 NULL,    /* init process */
 NULL,         /* init thread */
 NULL,         /* exit thread */
 NULL,    /* exit process */
 NULL,         /* exit master */
 NGX_MODULE_V1_PADDING
};
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;
 /* Http Output Buffer */
 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); 

 return ngx_http_output_filter(r, &out);
}
static char *
ngx_http_hello_world(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
 ngx_http_core_loc_conf_t *clcf ;
 /* register hanlder */
 clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);
 clcf->handler = ngx_http_hello_world_handler;
 return NGX_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
make install

e、配置nginx.conf

location= /hello {
 hello_world;
}

f、启动nginx,访问http://localhost/hello ,可以看到编写的helloworld模块输出的文字。
 
3.hello world模块分析
a.ngx_command_t函数用于定义包含模块指令的静态数组ngx_http_hello_world_commands

static ngx_command_t ngx_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.static u_char ngx_hello_world[] ="hello world" 则是输出到屏幕的字符串。
c.ngx_http_module_t用来定义结构体ngx_http_hello_world_module_ctx:

static ngx_http_module_t ngx_http_hello_world_module_ctx = {
 NULL,         /* 读入配置前调用*/
 NULL,          /* 读入配置后调用*/
 NULL,         /* 创建全局部分配置时调用 */
 NULL,         /* 初始化全局部分的配置时调用*/
 NULL,         /* 创建虚拟主机部分的配置时调用*/
 NULL,         /* 与全局部分配置合并时调用 */
 NULL,         /* 创建位置部分的配置时调用 */
 NULL         /* 与主机部分配置合并时调用*/
};

d.ngx_module_t定义结构体ngx_http_hello_world_module

ngx_module_t ngx_http_hello_world_module = {
 NGX_MODULE_V1,
 &ngx_http_hello_world_module_ctx,    /* module context */
 ngx_http_hello_world_commands,     /* module directives */
 NGX_HTTP_MODULE,      /* module type */
 NULL,         /* init master */
 NULL,         /* init module */
 NULL,    /* init process */
 NULL,         /* init thread */
 NULL,         /* exit thread */
 NULL,    /* exit process */
 NULL,         /* exit master */
 NGX_MODULE_V1_PADDING
};

e.处理函数,ngx_http_hello_world_handler,也是hello world 模块的核心部分。

static ngx_int_t
ngx_http_hello_world_handler(ngx_http_request_t *r)//ngx_http_request_t *r
//可以访问到客户端的头部和不久要发送的回复头部
{
 ngx_int_t  rc;
 ngx_buf_t *b;
 ngx_chain_t out;
 /* Http Output Buffer */
 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); 

 return ngx_http_output_filter(r, &out);
}

helloworld模块里面涉及最重要的数据就是ngx_module_t指针数组,这个指针数组包含了当前编译版本支持的所有模块,这个指针数组定义实在自动脚本生成的objs/ngx_modules.c中,如下:

 extern ngx_module_t ngx_core_module;
 extern ngx_module_t ngx_errlog_module;
 extern ngx_module_t ngx_conf_module;
 extern ngx_module_t ngx_events_module;
 extern ngx_module_t ngx_event_core_module;
 extern ngx_module_t ngx_epoll_module;
 extern ngx_module_t ngx_http_module;
 extern ngx_module_t ngx_http_core_module;
 extern ngx_module_t ngx_http_log_module;
 extern ngx_module_t ngx_http_upstream_module;
 extern ngx_module_t ngx_http_static_module;
 extern ngx_module_t ngx_http_autoindex_module;
 extern ngx_module_t ngx_http_index_module;
 extern ngx_module_t ngx_http_auth_basic_module;
 extern ngx_module_t ngx_http_access_module;
 extern ngx_module_t ngx_http_limit_zone_module;
 extern ngx_module_t ngx_http_limit_req_module;
 extern ngx_module_t ngx_http_geo_module;
 extern ngx_module_t ngx_http_map_module;
 extern ngx_module_t ngx_http_split_clients_module;
 extern ngx_module_t ngx_http_referer_module;
 extern ngx_module_t ngx_http_rewrite_module;
 extern ngx_module_t ngx_http_proxy_module;
 extern ngx_module_t ngx_http_fastcgi_module;
 extern ngx_module_t ngx_http_uwsgi_module;
 extern ngx_module_t ngx_http_scgi_module;
 extern ngx_module_t ngx_http_memcached_module;
 extern ngx_module_t ngx_http_empty_gif_module;
 extern ngx_module_t ngx_http_browser_module;
 extern ngx_module_t ngx_http_upstream_ip_hash_module;
 extern ngx_module_t ngx_http_cache_purge_module;
 extern ngx_module_t ngx_http_write_filter_module;
 extern ngx_module_t ngx_http_header_filter_module;
 extern ngx_module_t ngx_http_chunked_filter_module;
 extern ngx_module_t ngx_http_range_header_filter_module;
 extern ngx_module_t ngx_http_gzip_filter_module;
 extern ngx_module_t ngx_http_postpone_filter_module;
 extern ngx_module_t ngx_http_ssi_filter_module;
 extern ngx_module_t ngx_http_charset_filter_module;
 extern ngx_module_t ngx_http_userid_filter_module;
 extern ngx_module_t ngx_http_headers_filter_module;
 extern ngx_module_t ngx_http_copy_filter_module;
 extern ngx_module_t ngx_http_range_body_filter_module;
 extern ngx_module_t ngx_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_t ngx_core_module = {
 NGX_MODULE_V1,
 &ngx_core_module_ctx,     /* module context */
 ngx_core_commands,      /* module directives */
 NGX_CORE_MODULE,      /* module type */
 NULL,         /* init master */
 NULL,         /* init module */
 NULL,         /* init process */
 NULL,         /* init thread */
 NULL,         /* exit thread */
 NULL,         /* exit process */
 NULL,         /* exit master */
 NGX_MODULE_V1_PADDING
};

是不是跟helloworld里面非常相似了,没错,他们都是模块,唯一的不同点就是helloworld是你另外加进去的。
到现在位置也只是初探nginx的模块,最后提一张别人画的nginx的模块图,有助于接下来的学习。

(0)

相关推荐

  • 记录Nginx服务器的Split Clients模块配置过程

    ngx-http-split-clients模块基于一些特定条件分开客户端连接,(例如ip地址,请求头,cookies等) 示例配置: http { split-clients "${remote-addr}AAA" $variant { 0.5% .one; 2.0% .two; - ""; } server { location / { index index${variant}.html; 可以使用$cookie--作为来源来分离请求,来源字符串使用CRC32

  • Nginx配置srcache_nginx模块搭配Redis建立缓存系统

    1. nginx模块 --add-module=../modules/ngx_devel_kit-0.2.18 --add-module=../modules/set-misc-nginx-module-0.22rc8 --add-module=../modules/srcache-nginx-module-0.22 --add-module=../modules/redis-nginx-module-0.3.6 --add-module=../modules/redis2-nginx-modu

  • Nginx服务器中用于生成缩略图的模块配置教程

    ngx_image_thumb模块生成缩略图 ngx_image_thumb是nginx中用来生成缩略图的模块,生存缩略图的方法很多,本nginx模块主要功能是对请求的图片进行缩略/水印处理,支持文字水印和图片水印.支持自定义字体,文字大小,水印透明度,水印位置,判断原图是否是否大于指定尺寸才处理等等. 1. 编译方法 编译前请确认您的系统已经安装了libcurl-dev libgd2-dev libpcre-dev 依赖库 1.1 Debian / Ubuntu 系统举例 # 如果你没有安装G

  • 详解Nginx中的geo模块与利用其配置负载均衡的示例

    geo指令使用ngx_http_geo_module模块提供的.默认情况下,nginx有加载这个模块,除非人为的 --without-http_geo_module. ngx_http_geo_module模块可以用来创建变量,其值依赖于客户端IP地址. geo指令 语法: geo [$address] $variable { ... } 默认值: - 配置段: http 定义从指定的变量获取客户端的IP地址.默认情况下,nginx从$remote_addr变量取得客户端IP地址,但也可以从其他

  • Nginx服务器基本的模块配置和使用全攻略

    1. 安装nginx 1.1 选择稳定版本 我们编译安装nginx来定制自己的模块,机器CentOS 6.2 x86_64.首先安装缺少的依赖包: # yum -y install gcc gcc-c++ make libtool zlib zlib-devel openssl openssl-devel pcre pcre-devel 这些软件包如果yum上没有的话可以下载源码来编译安装,只是要注意编译时默认安装的目录,确保下面在安装nginx时能够找到这些动态库文件(ldconfig). 从

  • Linux下用Nginx作Perl程序服务器及其中Perl模块的配置

    perl + fastcgi + nginx搭建 nginx + fastcgi是php下最流行的一套环境了,那perl会不会也有fastcgi呢,当然有,今天来搭建下nginx下perl的fastcgi.性能方面也不亚于php,但是现在web程序php的流行程度perl无法比拟了,性能再好也枉然,但是部分小功能可以考虑使用perl的fastcgi来搞定.进入正题. 1. 准备软件环境: nginx:http://www.nginx.org perl:系统自带 fastcgi:http://ww

  • 在Nginx中配置image filter模块来实现动态生成缩略图

    先来看一下什么是nginx的image filter模块. HttpImageFilterModule用来裁剪过大的图片到指定大小,是nginx自带模块,默认不会开启 开启HttpImageFilterModule需要在编译要带上参数 --with-http_image_filter_module 该模块主要有两个指令: 语法: image_filter (test | size | resize width height | crop width height) 默认是: 无 可出现的上下文:

  • 详解Nginx服务器中配置Sysguard模块预防高负载的方案

    nginx做为HTTP服务器,有以下几项基本特性: 处理静态文件,索引文件以及自动索引:打开文件描述符缓冲. 无缓存的反向代理加速,简单的负载均衡和容错. FastCGI,简单的负载均衡和容错. 模块化的结构.包括gzipping, byte ranges, chunked responses,以及 SSI-filter等filter.如果由FastCGI或其它代理服务器处理单页中存在的多个SSI,则这项处理可以并行运行,而不需要相互等待. Nginx专为性能优化而开发,性能是其最重要的考量,实

  • 详解Nginx服务器的nginx-http-footer-filter模块配置

    nginx-http-footer-filter想必大家都觉得很陌生,那我们就来认识一下它吧,这是淘宝开发的nginx模块. 它用于nginx在响应请求文件底部追加内容. 今天抽空研究下这个插件,希望对大家有所帮助.为什么发现了这个插件,因为这几天公司需要在所有shtml文件后面追加一个js代码用来做统计(之前统计代码没加齐全),在寻求解决方法的过程中找到了它认识了它最后喜欢上了它,你可能以为我用这个插件去实现了我要的功能,其实在认识他之前我用shell脚本替换齐全了. 不过我还是决定研究测试一

  • 详解Nginx服务器中HTTP Headers相关的模块配置使用

    ngx_http_headers_module模块 一. 前言 ngx_http_headers_module模块提供了两个重要的指令add_header和expires,来添加 "Expires" 和 "Cache-Control" 头字段,对响应头添加任何域字段.add_header可以用来标示请求访问到哪台服务器上,这个也可以通过nginx模块nginx-http-footer-filter研究使用来实现.expires指令用来对浏览器本地缓存的控制. 二.

  • 详解Nginx的核心配置模块中对于请求体的接受流程

    本篇文章主要会介绍nginx中请求的接收流程,包括请求头的解析和请求体的读取流程. 首先介绍一下rfc2616中定义的http请求基本格式: Request = Request-Line *(( general-header | request-header | entity-header ) CRLF) CRLF [ message-body ] </span> 第一行是请求行(request line),用来说明请求方法,要访问的资源以及所使用的HTTP版本: Request-Line  

  • 详解Nginx服务器中map模块的配置与使用

    map指令使用ngx_http_map_module模块提供的.默认情况下,nginx有加载这个模块,除非人为的 --without-http_map_module. ngx_http_map_module模块可以创建变量,这些变量的值与另外的变量值相关联.允许分类或者同时映射多个值到多个不同值并储存到一个变量中,map指令用来创建变量,但是仅在变量被接受的时候执行视图映射操作,对于处理没有引用变量的请求时,这个模块并没有性能上的缺失. 一. ngx_http_map_module模块指令说明

  • 使用Lua编写Nginx服务器的认证模块的方法

    过去两天里,我解决了一个非常有趣的问题.我用一个nginx服务器作为代理,需要能够向其中添加一个认证层,使其能够使用外部的认证源(比如某个web应用)来进行验证,如果用户在外部认证源有账号,就可以在代理里认证通过. 需求一览 我考虑了几种解决方案,罗列如下: 用一个简单的Python/Flask模块来做代理和验证. 一个使用subrequests做验证的nginx模块(nginx目前可以做到这一点) 使用Lua编写一个nginxren认证模块 很显然,给整个系统添加额外请求将执行的不是很好,因为

随机推荐