PID221 / 烦人的幻灯片 ☆

前言

Nginx是眼下太盛的HTTP
Server之一,根据W3Techs的统计,目前世界排名(根据Alexa)前100万之网站遭遇,Nginx的占有率为6.8%。与Apache相比,Nginx在高并作情况下有伟大的性能优势。
Nginx属于典型的微内核设计,其基础非常简洁和淡雅,同时兼有十分大之而是扩展性。Nginx最初只是要给用于做反而往代理,后来乘HTTP核心的秋以及各种HTTP扩展模块的增长,Nginx越来越多吃用来取代Apache而独立承担HTTP
Server的事,例如目前淘宝内各个部门正愈来愈多下Nginx取代Apache,据作者询问,在腾讯和新浪等店铺吗在类似情况。
并且,大量之老三着扩大模块也教Nginx越来越强。例如,由淘宝的工程师清管(王晓哲)和人事来(章亦春)所付出之nginx_lua_module足以Lua语言嵌入到Nginx配置中,从而采取Lua极大增进了Nginx本身的编程能力,甚至可毫无配合其他脚本语言(如PHP或Python等),只因Nginx本身就是好兑现复杂工作的处理。而春来所支付的ngx_openresty逾由此购并LuaJIT顶零件,将Nginx本身变成了一个通通的行使开发平台。目前淘宝数据平台和产品部量子统计的出品还是依据ngx_openresty所开发。对ngxin_lua_module或ngx_openresty感兴趣的恋人可以参照我以显要词上受起底链接,后续我吗或会见刻画一些以及那个有关的篇章。
正文将会晤重要关注Nginx模块出入门与基础。目前Nginx的读书材料十分少,而恢宏模块出相关的资料几乎只有《Emiller’s
Guide To Nginx Module
Development》一软,此文十分藏,但是由Nginx版本的朝三暮四,其中有数情恐怕有硌过时。本文是笔者于研读这首文章和Nginx源代码的底蕴及,对协调修Nginx模块出的一个总结。本文将经一个完好无损的模块出实例讲解Nginx模块出的入门内容。
正文将因Nginx最新的1.0.0本子,操作系统环境也Linux(Ubuntu10.10)。
Nginx提要
付出Nginx扩展当然主要前提是本着Nginx有得的摸底,然而本文并无打算详细阐释Nginx的周,诸如Nginx的安和各种详细部署等情节都得以于Nginx官网的Document中找到,本文在此地仅会概括性描述有背后可能会见因此到的法则和定义。
Nginx在Linux下的装及运行
行使Nginx的率先步是下载Nginx源码包,例如1.0.0底下载地址也http://nginx.org/download/nginx-1.0.0.tar.gz。下载了晚因故tar命令解压缩,进入目录后安装过程和Linux下便步骤一样,例如我思念拿Nginx安装到/usr/local/nginx下,则执行如下命令:

./configure --prefix=/usr/local/nginx
make
make install

装好后方可直接利用下发号施令启动Nginx:

/usr/local/nginx/sbin/nginx

Nginx默认为Deamon进程启动,输入下列命令:

curl -i http://localhost/

尽管好检测Nginx是否已经成功运行。或者也得当浏览器被输入http://localhost/,应该好视Nginx的迎页面了。启动后如若想停Nginx可以应用:

/usr/local/nginx/sbin/nginx -s stop

Nginx配置文件中心组织
安排文件可以当是Nginx的魂魄,Nginx服务以起步时会见读入配置文件,而后续几乎所有动作行为都是遵照安排文件被的吩咐进行的,因此只要将Nginx本身作为一个处理器,那么Nginx的安排文件可以看成是全体之次序指令。
脚是一个Nginx配置文件之实例:

#user nobody;
worker_processes 8;
error_log logs/error.log;
pid logs/nginx.pid;
events {
 worker_connections 1024;
}
http {
 include mime.types;
 default_type application/octet-stream;

 sendfile on;
 #tcp_nopush on;
 keepalive_timeout 65;
 #gzip on;

 server {
 listen 80;
 server_name localhost;
 location / {
 root /home/yefeng/www;
 index index.html index.htm;
 }
 #error_page 404 /404.html;
 # redirect server error pages to the static page /50x.html
 #
 error_page 500 502 503 504 /50x.html;
 location = /50x.html {
 root html;
 }
 }
}

Nginx配置文件是纯粹文本文件,你可以为此别样公文编辑器如vim或emacs打开她,通常她见面在nginx安装目录的conf下,如我之nginx安装在/usr/local/nginx,主配置文件默认放在/usr/local/nginx/conf/nginx.conf。
其中“#”表示此行是注释,由于笔者为求学扩大开发安装了一个纯粹的Nginx,因此配置文件并未通过极其多反。
Nginx的配备文件是坐block的款型组织的,一个block通常使用大括哀号“{}”表示。block分为几独层级,整个配置文件也main层级,这是绝充分之层级;在main层级下可以产生event、http等层级,而http中而且见面起server
block,server block中可以涵盖location block。
每个层级可以有好的授命(Directive),例如worker_processes是一个main层级指令,它指定Nginx服务之Worker进程数量。有的指令只能在一个层级中配置,如worker_processes只能在于main中,而有的指令可以有让多个层级,在这种景象下,子block会继承父block的配备,同时如果子block配置了同父block不同之指令,则会盖掉父block的部署。指令的格式是“指令名
参数1 参数2 … 参数N;”,注意参数间可用任意数量空格分隔,最后使加分号。
当开发Nginx
HTTP扩展模块过程中,需要特别注意的是main、server和location三独层级,因为扩展模块通常允许指定新的布置指令在当下三只层级中。
末段只要提到的凡部署文件是足以蕴涵的,如上面配置文件被“include
mime.types”就富含了mine.types这个布局文件,此文件指定了各种HTTP
Content-type。
一般的话,一个server
block表示一个Host,而内部的一个location则代表一个路由映射规则,这点儿只block可以说凡是HTTP配置的着力。
生图是Nginx配置文件一般结构图示。

有关Nginx配置的复多内容要参考Nginx官方文档。
Nginx模块工作规律概述
(Nginx本身支持多模块,如HTTP模块、EVENT模块和MAIL模块,本文特谈谈HTTP模块)
Nginx本身做的干活实际上甚少,当它接受一个HTTP请求时,它只有是通过搜寻配置文件拿本次请求映射到一个location
block,而之location中所安排的依次指令则会启动不同之模块去完成工作,因此模块可看作Nginx真正的麻烦工作者。通常一个location中的指令会涉及一个handler模块和多只filter模块(当然,多独location可以复用同一个模块)。handler模块负责处理要,完成响应内容之变化,而filter模块对响应内容开展处理。因此Nginx模块出分为handler开发与filter开发(本文不考虑load-balancer模块)。下图显示了一样糟糕正常请求与应的过程。

Nginx模块出实战
脚本文展示一个简的Nginx模块出都经过,我们出一个叫echo的handler模块,这个模块功能非常简单,它接受“echo”指令,指令可指定一个字符串参数,模块会输出这个字符串作为HTTP响应。例如,做如下配置:

location /echo {
 echo "hello nginx";
}

则访问http://hostname/echo经常会见输出hello
nginx。
直观来拘禁,要实现这效果要三步:1、读入配置文件中echo指令及其参数;2、进行HTTP包装(添加HTTP头等工作);3、将结果返回给客户端。下面本文将分部介绍任何模块的付出过程。
概念模块配置结构
率先我们要一个构造用于存储于部署文件被读上的相干指令参数,即模块配置信息结构。根据Nginx模块出规则,这个结构的命名规则为ngx_http_[module-name]_[main|srv|loc]_conf_t。其中main、srv和loc分别用于表示一致模块于三重合block中的布局信息。这里我们的echo模块只需要周转在loc层级下,需要仓储一个字符串参数,因此我们得定义如下的模块配置:

typedef struct {
 ngx_str_t ed;
} ngx_http_echo_loc_conf_t;

里面字段ed用于存储echo指令指定的内需输出的字符串。注意这里ed的色,在Nginx模块出被动用ngx_str_t类型表示字符串,这个类型定义在core/ngx_string中:

typedef struct {
 size_t len;
 u_char *data;
} ngx_str_t;

个中有数只字段分别表示字符串的尺寸以及数目起始地址。注意在Nginx源代码中针对数据类型进行了别称定义,如ngx_int_t为intptr_t的别称,为了保持一致,在付出Nginx模块时为应当利用这些Nginx源码定义之项目而毫无采取C原生类型。除了ngx_str_t外,其它三单常因此的nginx
type分别吗:

typedef intptr_t ngx_int_t;
typedef uintptr_t ngx_uint_t;
typedef intptr_t ngx_flag_t;

现实定义请参考core/ngx_config.h。关于intptr_t和uintptr_t请参考C99中的stdint.h或http://linux.die.net/man/3/intptr\_t。
概念指令
一个Nginx模块往往吸收一届多单命,echo模块接收一个限令“echo”。Nginx模块使用一个ngx_command_t数组表示模块所能接的保有模块,其中各一个因素表示一个长达指令。ngx_command_t是ngx_command_s的一个又称(Nginx习惯被采用“_s”后缀命名结构体,然后typedef一个同名“_t”后缀名称作为这结构体的花色名),ngx_command_s定义在
core/ngx_config_file.h中:

struct ngx_command_s {
 ngx_str_t name;
 ngx_uint_t type;
 char *(*set)(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
 ngx_uint_t conf;
 ngx_uint_t offset;
 void *post;
};

内部name是歌词条指令的称呼,type使用掩码标志位方式安排指令参数,相关可用type定义在core/ngx_config_file.h中:

#define NGX_CONF_NOARGS 0x00000001
#define NGX_CONF_TAKE1 0x00000002
#define NGX_CONF_TAKE2 0x00000004
#define NGX_CONF_TAKE3 0x00000008
#define NGX_CONF_TAKE4 0x00000010
#define NGX_CONF_TAKE5 0x00000020
#define NGX_CONF_TAKE6 0x00000040
#define NGX_CONF_TAKE7 0x00000080
#define NGX_CONF_MAX_ARGS 8
#define NGX_CONF_TAKE12 (NGX_CONF_TAKE1|NGX_CONF_TAKE2)
#define NGX_CONF_TAKE13 (NGX_CONF_TAKE1|NGX_CONF_TAKE3)
#define NGX_CONF_TAKE23 (NGX_CONF_TAKE2|NGX_CONF_TAKE3)
#define NGX_CONF_TAKE123 (NGX_CONF_TAKE1|NGX_CONF_TAKE2|NGX_CONF_TAKE3)
#define NGX_CONF_TAKE1234 (NGX_CONF_TAKE1|NGX_CONF_TAKE2|NGX_CONF_TAKE3 \
 |NGX_CONF_TAKE4)
#define NGX_CONF_ARGS_NUMBER 0x000000ff
#define NGX_CONF_BLOCK 0x00000100
#define NGX_CONF_FLAG 0x00000200
#define NGX_CONF_ANY 0x00000400
#define NGX_CONF_1MORE 0x00000800
#define NGX_CONF_2MORE 0x00001000
#define NGX_CONF_MULTI 0x00002000

其中NGX_CONF_NOARGS代表是命令不受参数,NGX_CON
F_TAKE1-7表示精确接收1-7独,NGX_CONF_TAKE12代表接受1要么2个参数,NGX_CONF_1MORE表示至少一个参数,NGX_CONF_FLAG表示接受“on|off”……
set是一个函数指针,用于指定一个参数转化函数,这个函数一般是拿部署文件被有关指令的参数转化成要的格式并存入配置结构体。Nginx预定义了一些变函数,可以好我们调用,这些函数定义在core/ngx_conf_file.h中,一般以“_slot”结尾,例如ngx_conf_set_flag_slot将“on或off”转换为“1或0”,再如ngx_conf_set_str_slot将裸字符串转化为ngx_str_t。
conf用于指定Nginx相应安排文件内存其实地址,一般可以由此嵌入常量指定,如NGX_HTTP_LOC_CONF_OFFSET,offset指定此条指令的参数的偏移量。
下是echo模块的吩咐定义:

static ngx_command_t ngx_http_echo_commands[] = {
 { ngx_string("echo"),
 NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
 ngx_http_echo,
 NGX_HTTP_LOC_CONF_OFFSET,
 offsetof(ngx_http_echo_loc_conf_t, ed),
 NULL },
 ngx_null_command
};

令数组的命名规则也ngx_http_[module-name]_commands,注意数组最后一个元素如ngx_null_command结束。
参数转化函数的代码为:

static char *
ngx_http_echo(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_echo_handler;
 ngx_conf_set_str_slot(cf,cmd,conf);
 return NGX_CONF_OK;
}

这个函数除了调用ngx_conf_set_str_slot转化echo指令的参数外,还将改了基本模块配置(也即是其一location的布),将那handler替换为我们编辑的handler:ngx_http_echo_handler。这样尽管挡了这location的默认handler,使用ngx_http_echo_handler产生HTTP响应。
缔造合并配置信息
产一致步是概念模块Context。
这里首先需定义一个ngx_http_module_t类型的结构体变量,命名规则也ngx_http_[module-name]_module_ctx,这个组织要用来定义各个Hook函数。下面是echo模块的context结构:

static ngx_http_module_t ngx_http_echo_module_ctx = {
 NULL, /* preconfiguration */
 NULL, /* postconfiguration */
 NULL, /* create main configuration */
 NULL, /* init main configuration */
 NULL, /* create server configuration */
 NULL, /* merge server configuration */
 ngx_http_echo_create_loc_conf, /* create location configration */
 ngx_http_echo_merge_loc_conf /* merge location configration */
};

好看来一共发8单Hook注入点,分别会见在不同随时让Nginx调用,由于我们的模块仅仅用于location域,这里拿未待之注入点设为NULL即可。其中create_loc_conf用于初始化一个布局结构体,如为布局结构体分配内存等工作;merge_loc_conf用于将那父block的布局信息统一到这个结构体中,也不怕是促成配置的继续。这半单函数会吃Nginx自动调用。注意这里的命名规则:ngx_http_[module-name][create|merge][main|srv|loc]_conf。
脚是echo模块这个点儿个函数的代码:

static void *
ngx_http_echo_create_loc_conf(ngx_conf_t *cf)
{
 ngx_http_echo_loc_conf_t *conf;
 conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_echo_loc_conf_t));
 if (conf == NULL) {
 return NGX_CONF_ERROR;
 }
 conf->ed.len = 0;
 conf->ed.data = NULL;
 return conf;
}
static char *
ngx_http_echo_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
{
 ngx_http_echo_loc_conf_t *prev = parent;
 ngx_http_echo_loc_conf_t *conf = child;
 ngx_conf_merge_str_value(conf->ed, prev->ed, "");
 return NGX_CONF_OK;
}

其中ngx_pcalloc用于在Nginx内存池中分配一块空间,是pcalloc的一个卷入。使用ngx_pcalloc分配的内存空间不必手工free,Nginx会自行保管,在方便是否释放。
create_loc_conf新建一个ngx_http_echo_loc_conf_t,分配内存,并初始化其中的数,然后回这个组织的指针;merge_loc_conf将父block域的布信息统一到create_loc_conf新建的部署结构体中。
其中ngx_conf_merge_str_value不是一个函数,而是一个巨大,其定义在core/ngx_conf_file.h中:

#define ngx_conf_merge_str_value(conf, prev, default) \
 if (conf.data == NULL) { \
 if (prev.data) { \
 conf.len = prev.len; \
 conf.data = prev.data; \
 } else { \
 conf.len = sizeof(default) - 1; \
 conf.data = (u_char *) default; \
 } \
 }

并且可以看,core/ngx_conf_file.h还定义了好多merge
value的宏用于merge各种数据。它们的一言一行比较相似:使用prev填充conf,如果prev的多少吧空则使用default填充。
编写Handler
脚的干活是编辑handler。handler可以说凡是模块中的确行事的代码,它要出以下四起职责:
读入模块配置。
处理效果业务。
产生HTTP header。
产生HTTP body。
脚先贴出echo模块的代码,然后通过分析代码的计介绍如何实现即时四步。这同一片的代码比较复杂:

static ngx_int_t
ngx_http_echo_handler(ngx_http_request_t *r)
{
 ngx_int_t rc;
 ngx_buf_t *b;
 ngx_chain_t out;
 ngx_http_echo_loc_conf_t *elcf;
 elcf = ngx_http_get_module_loc_conf(r, ngx_http_echo_module);
 if(!(r->method & (NGX_HTTP_HEAD|NGX_HTTP_GET|NGX_HTTP_POST)))
 {
 return NGX_HTTP_NOT_ALLOWED;
 }
 r->headers_out.content_type.len = sizeof("text/html") - 1;
 r->headers_out.content_type.data = (u_char *) "text/html";
 r->headers_out.status = NGX_HTTP_OK;
 r->headers_out.content_length_n = elcf->ed.len;
 if(r->method == NGX_HTTP_HEAD)
 {
 rc = ngx_http_send_header(r);
 if(rc != NGX_OK)
 {
 return rc;
 }
 }
 b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t));
 if(b == NULL)
 {
 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "Failed to allocate response buffer.");
 return NGX_HTTP_INTERNAL_SERVER_ERROR;
 }
 out.buf = b;
 out.next = NULL;
 b->pos = elcf->ed.data;
 b->last = elcf->ed.data + (elcf->ed.len);
 b->memory = 1;
 b->last_buf = 1;
 rc = ngx_http_send_header(r);
 if(rc != NGX_OK)
 {
 return rc;
 }
 return ngx_http_output_filter(r, &out);
}

handler会接收一个ngx_http_request_t指针类型的参数,这个参数对一个ngx_http_request_t结构体,此结构体存储了这次HTTP请求的有消息,这个组织定义在

http/ngx_http_request.h中:
struct ngx_http_request_s {
 uint32_t signature; /* "HTTP" */
 ngx_connection_t *connection;
 void **ctx;
 void **main_conf;
 void **srv_conf;
 void **loc_conf;
 ngx_http_event_handler_pt read_event_handler;
 ngx_http_event_handler_pt write_event_handler;
#if (NGX_HTTP_CACHE)
 ngx_http_cache_t *cache;
#endif
 ngx_http_upstream_t *upstream;
 ngx_array_t *upstream_states;
 /* of ngx_http_upstream_state_t */
 ngx_pool_t *pool;
 ngx_buf_t *header_in;
 ngx_http_headers_in_t headers_in;
 ngx_http_headers_out_t headers_out;
 ngx_http_request_body_t *request_body;
 time_t lingering_time;
 time_t start_sec;
 ngx_msec_t start_msec;
 ngx_uint_t method;
 ngx_uint_t http_version;
 ngx_str_t request_line;
 ngx_str_t uri;
 ngx_str_t args;
 ngx_str_t exten;
 ngx_str_t unparsed_uri;
 ngx_str_t method_name;
 ngx_str_t http_protocol;
 ngx_chain_t *out;
 ngx_http_request_t *main;
 ngx_http_request_t *parent;
 ngx_http_postponed_request_t *postponed;
 ngx_http_post_subrequest_t *post_subrequest;
 ngx_http_posted_request_t *posted_requests;
 ngx_http_virtual_names_t *virtual_names;
 ngx_int_t phase_handler;
 ngx_http_handler_pt content_handler;
 ngx_uint_t access_code;
 ngx_http_variable_value_t *variables;
 /* ... */
}

由于ngx_http_request_s定义比较长,这里我单独截取了一样部分。可以看出里边有诸如uri,args和request_body等HTTP常用信息。这里用特别注意的几乎单字段是headers_in、headers_out和chain,它们各自代表request
header、response header和输出数据缓冲区链表(缓冲区链表是Nginx
I/O中之根本内容,后面会独自介绍)。
首先步是取模块配置信息,这同样块要简单以ngx_http_get_module_loc_conf就足以了。
其次步是功力逻辑,因为echo模块非常简单,只是简单输出一个字符串,所以这里没有效应逻辑代码。
老三步是安response
header。Header内容可以经填写headers_out实现,我们这边只有设置了Content-type和Content-length等基本内容,ngx_http_headers_out_t定义了拥有可以装的HTTP
Response Header信息:

typedef struct {
 ngx_list_t headers;
 ngx_uint_t status;
 ngx_str_t status_line;
 ngx_table_elt_t *server;
 ngx_table_elt_t *date;
 ngx_table_elt_t *content_length;
 ngx_table_elt_t *content_encoding;
 ngx_table_elt_t *location;
 ngx_table_elt_t *refresh;
 ngx_table_elt_t *last_modified;
 ngx_table_elt_t *content_range;
 ngx_table_elt_t *accept_ranges;
 ngx_table_elt_t *www_authenticate;
 ngx_table_elt_t *expires;
 ngx_table_elt_t *etag;
 ngx_str_t *override_charset;
 size_t content_type_len;
 ngx_str_t content_type;
 ngx_str_t charset;
 u_char *content_type_lowcase;
 ngx_uint_t content_type_hash;
 ngx_array_t cache_control;
 off_t content_length_n;
 time_t date_time;
 time_t last_modified_time;
} ngx_http_headers_out_t;

此间并无分包有HTTP头信息,如果急需好采取agentzh(春来)开发之Nginx模块HttpHeadersMore于命令中指定更多之Header头信息。
安好头信息后下ngx_http_send_header就可以头信息输出,ngx_http_send_header接受一个ngx_http_request_t类型的参数。
季步也是最要之一律步是输出Response
body。这里首先要询问Nginx的I/O机制,Nginx允许handler一潮发同样组输出,可以有多次,Nginx将出口组织成一个单链表结构,链表中的每个节点是一个chain_t,定义在core/ngx_buf.h:

struct ngx_chain_s {
 ngx_buf_t *buf;
 ngx_chain_t *next;
};

其中ngx_chain_t是ngx_chain_s的别名,buf为某数缓冲区的指针,next指为下一个链表节点,可以见到这是一个非常简单的链表。ngx_buf_t的概念比较长同时很复杂,这里就无粘出了,请自行参考core/ngx_buf.h。ngx_but_t中比较主要之凡pos和last,分别表示如缓冲区多少在内存中的起始地址与终极地址,这里我们以部署中字符串传上,last_buf是一个位域,设为1意味此缓冲区是链表中最后一个素,为0表示后面还有元素。因为我们只来相同组数据,所以缓冲区链表中才发一个节点,如果急需输入多组数据只是将各组数据放入不同缓冲区后插入到链表。下图显示了Nginx缓冲链表的构造:

缓冲数据准备好后,用ngx_http_output_filter就可以输出了(会送及filter进行各种过滤处理)。ngx_http_output_filter的率先个参数为ngx_http_request_t结构,第二单吗出口链表的序幕地址&out。ngx_http_out_put_filter会遍历链表,输出所有数据。
以上就是是handler的富有工作,请对照描述理解地方粘发的handler代码。
组合Nginx Module
地方就了Nginx模块各种零件的支出下面就用这些成起来了。一个Nginx模块于定义也一个ngx_module_t结构,这个组织的字段很多,不过开和最后若干字段一般可以透过Nginx内置的宏去填充,下面是咱echo模块的模块主体定义:

ngx_module_t ngx_http_echo_module = {
 NGX_MODULE_V1,
 &ngx_http_echo_module_ctx, /* module context */
 ngx_http_echo_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
};

起来和末段分别就此NGX_MODULE_V1和NGX_MODULE_V1_PADDING
填充了若干字段,就无去追了。这里最主要用填的音信从上到下以一一为context、指令数组、模块类型以及几特定事件的回调处理函数(不待好打否NULL),其中内容还是比较好明的,注意我们的echo是一个HTTP模块,所以这里路是NGX_HTTP_MODULE,其它可用类型还有NGX_EVENT_MODULE(事件处理模块)和NGX_MAIL_MODULE(邮件模块)。
这么,整个echo模块就写好了,下面给出echo模块的完好代码:

/*
* Copyright (C) Eric Zhang
*/
#include <ngx_config.h>
#include <ngx_core.h>
#include <ngx_http.h>
/* Module config */
typedef struct {
 ngx_str_t ed;
} ngx_http_echo_loc_conf_t;
static char *ngx_http_echo(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
static void *ngx_http_echo_create_loc_conf(ngx_conf_t *cf);
static char *ngx_http_echo_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child);
/* Directives */
static ngx_command_t ngx_http_echo_commands[] = {
 { ngx_string("echo"),
 NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
 ngx_http_echo,
 NGX_HTTP_LOC_CONF_OFFSET,
 offsetof(ngx_http_echo_loc_conf_t, ed),
 NULL },
 ngx_null_command
};
/* Http context of the module */
static ngx_http_module_t ngx_http_echo_module_ctx = {
 NULL, /* preconfiguration */
 NULL, /* postconfiguration */
 NULL, /* create main configuration */
 NULL, /* init main configuration */
 NULL, /* create server configuration */
 NULL, /* merge server configuration */
 ngx_http_echo_create_loc_conf, /* create location configration */
 ngx_http_echo_merge_loc_conf /* merge location configration */
};
/* Module */
ngx_module_t ngx_http_echo_module = {
 NGX_MODULE_V1,
 &ngx_http_echo_module_ctx, /* module context */
 ngx_http_echo_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
};
/* Handler function */
static ngx_int_t
ngx_http_echo_handler(ngx_http_request_t *r)
{
 ngx_int_t rc;
 ngx_buf_t *b;
 ngx_chain_t out;
 ngx_http_echo_loc_conf_t *elcf;
 elcf = ngx_http_get_module_loc_conf(r, ngx_http_echo_module);
 if(!(r->method & (NGX_HTTP_HEAD|NGX_HTTP_GET|NGX_HTTP_POST)))
 {
 return NGX_HTTP_NOT_ALLOWED;
 }
 r->headers_out.content_type.len = sizeof("text/html") - 1;
 r->headers_out.content_type.data = (u_char *) "text/html";
 r->headers_out.status = NGX_HTTP_OK;
 r->headers_out.content_length_n = elcf->ed.len;
 if(r->method == NGX_HTTP_HEAD)
 {
 rc = ngx_http_send_header(r);
 if(rc != NGX_OK)
 {
 return rc;
 }
 }
 b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t));
 if(b == NULL)
 {
 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "Failed to allocate response buffer.");
 return NGX_HTTP_INTERNAL_SERVER_ERROR;
 }
 out.buf = b;
 out.next = NULL;
 b->pos = elcf->ed.data;
 b->last = elcf->ed.data + (elcf->ed.len);
 b->memory = 1;
 b->last_buf = 1;
 rc = ngx_http_send_header(r);
 if(rc != NGX_OK)
 {
 return rc;
 }
 return ngx_http_output_filter(r, &out);
}
static char *
ngx_http_echo(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_echo_handler;
 ngx_conf_set_str_slot(cf,cmd,conf);
 return NGX_CONF_OK;
}
static void *
ngx_http_echo_create_loc_conf(ngx_conf_t *cf)
{
 ngx_http_echo_loc_conf_t *conf;
 conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_echo_loc_conf_t));
 if (conf == NULL) {
 return NGX_CONF_ERROR;
 }
 conf->ed.len = 0;
 conf->ed.data = NULL;
 return conf;
}
static char *
ngx_http_echo_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
{
 ngx_http_echo_loc_conf_t *prev = parent;
 ngx_http_echo_loc_conf_t *conf = child;
 ngx_conf_merge_str_value(conf->ed, prev->ed, "");
 return NGX_CONF_OK;
}

Nginx模块的安装
Nginx不支持动态链接模块,所以安装模块需要将模块代码和Nginx源代码进行重复编译。安装模块的步调如下:
1、编写模块config文件,这个文件要放在和模块源代码文件在同等目录下。文件内容如下:

ngx_addon_name=模块完整名称
HTTP_MODULES="$HTTP_MODULES 模块完整名称"
NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/源代码文件名"

2、进入Nginx源代码,使用下发号施令编译安装
./configure –prefix=安装目录 –add-module=模块源代码文件目录

make
make install

如此即便好安装了,例如,我之源代码文件放在/home/yefeng/ngxdev/ngx_http_echo下,我的config文件为:

ngx_addon_name=ngx_http_echo_module
HTTP_MODULES="$HTTP_MODULES ngx_http_echo_module"
NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/ngx_http_echo_module.c"

编译安装命令为:

./configure --prefix=/usr/local/nginx --add-module=/home/yefeng/ngxdev/ngx_http_echo
make
sudo make install

这般echo模块就为设置在自己的Nginx上了,下面测试一下,修改配置文件,增加以下一起配置:

location /echo {
 echo "This is my first nginx module!!!";
}

下一场据此curl测试一下:

curl -i http://localhost/echo

结果如下:

足见到模块已正常工作了,也得以于浏览器被打开网址,就可以看到结果:

更尖锐之就学
本文只是略介绍了Nginx模块的开销进程,由于篇幅的故,不克面面俱到。因为时Nginx的修资料十分少,如果读者希望更深入学Nginx的法则同模块出,那么看源代码是无比好之道。在Nginx源代码的core/下推广起Nginx的着力代码,对解Nginx的里边工作体制很有帮扶,http/目录下产生Nginx
HTTP相关的落实,http/module下推广起大量置http模块,可供应读者学习模块的支出,另外在http://wiki.nginx.org/3rdPartyModules及闹恢宏帅之老三正值模块,也是殊好之读书材料。
倘有意见建议或问题欢迎发送邮件及ericzhang.buaa@gmail.com。希望本文对你有帮助!!!
参考文献
[1] Evan Miller, Emiller’s Guide To Nginx Module Development.
http://www.evanmiller.org/nginx-modules-guide.html,
2009
[2]
http://wiki.nginx.org/Configuration
[3] Clément Nedelcu, Nginx Http Server. Packt Publishing, 2010

分享自:
codinglabs。

  • 交付你的代码
  • 翻看讨论和题解

统计 1

若还木有开了啊

自我的状态

 

 

 

 

翻最后一破测评记录

统计 2

统计 3

质地还未可知统计出来啊~

问题评价

质量

★★★★★

★★★★☆

★★★☆☆

★★☆☆☆

★☆☆☆☆

0%

0%

0%

0%

0%

统计 4

通过人数 186 / 337

经过统计

 

顶缺乏耗时

0ms

极小内存

0KB

统计 5

其它

题材标签

类型

其它 

题材叙述

李教授被今天下午做一个充分关键之发言。不幸的凡他无是一个那个好干净的丁,他管自己做演讲要为此底幻灯片随便堆放于共同。因此,演讲之前他只得失去理这些幻灯片。做也一个器效率的专家,他希望尽量简单地形成她。情况是这般,教授这次讲演一共要用n张幻灯片(n<=26),这n张幻灯片按照演讲要下的各个已经用数字1,2,…,n在点编上了号。因为幻灯片是透明底,所以我们无克转圈清各个一个数字所对应之幻灯片。

本咱们因而十分写字母A,B,C,。。。再次将幻灯片依次编上号,如样例所示,我们得快发现编号为A的幻灯片是第4张,把她减少出来后我们还要可规定编号为C的幻灯片是第2布置,。。。

而的任务是编制一个序,把幻灯片的数字编号和字母编号对应起来,显然这种对应相应是绝无仅有的;若是出现强对应的图景也许某些数字编号与字母对诺休起来,我们不怕如对许是无法兑现的。

输入格式

第一实行仅生一个数n,表示有n张幻灯片,接下去的n行第行包括4单整数Xmin,Xmax,Ymin,Ymax(整数之间为此空格分开),为幻灯片的坐标(该区域为幻灯片),这n张幻灯片按该在输入文件被起的次第由前面至后依次编号为A,B,C,。。。再接下来的n行依次为n个数字编号的坐标X,Y,显然在幻灯片之外是勿见面产生数字之。

(其实是键盘输入了哪)

输出格式

而对许可实现,你的出口应该包括n行,每一样表现一个字母和一个数字,中间以一个空格隔开,并且各行以字母的升序排列,注意输出的假名要大写并且顶格;反之,若是对许无法实现,在文书之率先执行顶格输出None即可。行首行末无多余空格。

(其实是屏幕输出了啦。。。)

样例输入

4
6  22  10  20
4  18  6   16
8  20  2   18
10 24  4   8
9  15
19 17
11 7
21 11

输出

A4
B1
C2
D3
暴力时有发生奇迹暴力时有发生奇迹暴力时有发生奇迹暴力时有发生奇迹暴力时有发生奇迹暴力时有发生奇迹暴力时有发生奇迹暴力时有发生奇迹暴力时有发生奇迹暴力时有发生奇迹暴力时有发生奇迹暴力时有发生奇迹暴力时有发生奇迹暴力时有发生奇迹暴力时有发生奇迹暴力时有发生奇迹暴力时有发生奇迹暴力时有发生奇迹暴力时有发生奇迹暴力时有发生奇迹暴力时有发生奇迹暴力时有发生奇迹暴力时有发生奇迹暴力时有发生奇迹暴力时有发生奇迹暴力时有发生奇迹暴力时有发生奇迹暴力时有发生奇迹暴力时有发生奇迹暴力时有发生奇迹暴力时有发生奇迹暴力时有发生奇迹暴力时有发生奇迹暴力时有发生奇迹暴力时有发生奇迹暴力时有发生奇迹暴力时有发生奇迹暴力时有发生奇迹暴力时有发生奇迹暴力时有发生奇迹暴力时有发生奇迹暴力时有发生奇迹暴力时有发生奇迹暴力时有发生奇迹暴力时有发生奇迹暴力时有发生奇迹暴力时有发生奇迹暴力时有发生奇迹暴力时有发生奇迹暴力时有发生奇迹暴力时有发生奇迹暴力时有发生奇迹暴力时有发生奇迹暴力时有发生奇迹暴力时有发生奇迹暴力时有发生奇迹暴力时有发生奇迹暴力时有发生奇迹暴力时有发生奇迹暴力时有发生奇迹暴力时有发生奇迹暴力时有发生奇迹暴力时有发生奇迹暴力时有发生奇迹暴力时有发生奇迹暴力时有发生奇迹暴力时有发生奇迹暴力时有发生奇迹暴力时有发生奇迹暴力时有发生奇迹暴力时有发生奇迹暴力时有发生奇迹暴力时有发生奇迹暴力时有发生奇迹暴力时有发生奇迹暴力时有发生奇迹暴力时有发生奇迹暴力时有发生奇迹暴力时有发生奇迹暴力时有发生奇迹暴力时有发生奇迹暴力时有发生奇迹暴力时有发生奇迹暴力时有发生奇迹暴力时有发生奇迹暴力时有发生奇迹暴力时有发生奇迹暴力时有发生奇迹暴力时有发生奇迹暴力时有发生奇迹暴力时有发生奇迹暴力时有发生奇迹暴力时有发生奇迹暴力时有发生奇迹暴力时有发生奇迹暴力时有发生奇迹暴力时有发生奇迹暴力时有发生奇迹暴力时有发生奇迹暴力时有发生奇迹暴力时有发生奇迹暴力时有发生奇迹暴力时有发生奇迹暴力时有发生奇迹暴力时有发生奇迹暴力时有发生奇迹暴力时有发生奇迹暴力时有发生奇迹暴力时有发生奇迹暴力时有发生奇迹暴力时有发生奇迹暴力时有发生奇迹暴力时有发生奇迹暴力时有发生奇迹暴力时有发生奇迹暴力时有发生奇迹暴力时有发生奇迹暴力时有发生奇迹暴力时有发生奇迹暴力时有发生奇迹暴力时有发生奇迹暴力时有发生奇迹暴力时有发生奇迹暴力时有发生奇迹暴力时有发生奇迹暴力时有发生奇迹暴力时有发生奇迹暴力时有发生奇迹暴力时有发生奇迹暴力时有发生奇迹暴力时有发生奇迹暴力时有发生奇迹暴力时有发生奇迹暴力时有发生奇迹暴力时有发生奇迹、】

 

 1 #include<iostream>
 2 #include<cstring>
 3 #include<cstdio>
 4 using namespace std;
 5 struct node
 6 {
 7     int xmin;
 8     int xmax;
 9     int ymin;
10     int ymax;
11     int vis;
12     int bj;
13 }a[1001];
14 struct zb
15 {
16     int x;
17     int y;
18     int vis;
19     int bj;
20 }b[1001];
21 int n;
22 int flag=0;
23 char hh='A';
24 int ans[1001];
25 void dfs(int p)
26 {
27     if(p==n+1)
28     {
29         if(flag==0)
30         {
31             for(int i=1;i<=n;i++)
32             {
33                 ans[i]=a[i].bj;
34             }
35             flag=1;
36         }
37         else 
38         {
39             for(int i=1;i<=n;i++)
40             {
41                 if(a[i].bj!=ans[i])
42                 {
43                     printf("None");
44                     flag=2;
45                     return;
46                 }
47             }
48         }
49         
50         /*for(int i=1;i<=n;i++)
51         printf("%c %d\n",hh,a[i].bj);
52         flag=1;
53         return;*/
54     }
55     for(int j=1;j<=n;j++)
56         {
57             if(a[j].vis==0)
58             {
59                 for(int k=1;k<=n;k++)
60                 {
61                     if(a[j].xmin<b[k].x&&a[j].xmax>b[k].x&&a[j].ymin<b[k].y&&a[j].ymax>b[k].y&&b[k].vis==0)
62                     {
63                         a[j].vis=1;
64                         b[k].vis=1;
65                         a[j].bj=k;
66                         dfs(p+1);
67                         if(flag==2)return;    
68                         b[k].vis=0;
69                         a[j].vis=0;
70                     }
71                 }
72                 
73             }
74             
75         }
76 }
77 int main()
78 {
79     
80     scanf("%d",&n);
81     for(int i=1;i<=n;i++)
82         scanf("%d%d%d%d",&a[i].xmin,&a[i].xmax,&a[i].ymin,&a[i].ymax);
83     for(int i=1;i<=n;i++)
84         scanf("%d%d",&b[i].x,&b[i].y);
85     dfs(1);
86     if(flag==1)
87     for(int i=1;i<=n;i++)
88     {
89         printf("%c%d\n",hh++,ans[i]);
90     }
91     return 0;
92     
93 }