(为了让流程更清晰,我删掉了各种错误处理与返回值判断等等,实际中还是要判断判断滴)
1、先看处理请求的handler,不是智障应该都能看懂:
static ngx_int_t
ngx_http_hello_handler(ngx_http_request_t *r)
{
//丢弃掉请求的body
ngx_http_discard_request_body(r);
ngx_str_t response = ngx_string("Hello world");
//分配内存,因为是异步的关系,所以不能发送栈区内存中的数据
//否则栈被析构了请求还没发,等框架准备好了再来发的时候,那块内存就已经不是“Hello world”了
ngx_buf_t* b;
b = ngx_create_temp_buf(r->pool, response.len);
ngx_memcpy(b->pos, response.data, response.len);
//以下步骤是必须的,否则不会发送任何相应
b->last = b->pos + response.len;
b->last_buf = 1;
r->headers_out.status = NGX_HTTP_OK;
r->headers_out.content_length_n = response.len;
ngx_http_send_header(r);
//一个ngx_buf_t的链表
ngx_chain_t out;
out.buf = b;
out.next = NULL;
return ngx_http_output_filter(r, &out);
}
那么问题来了,这tmd怎么被调用的?
static ngx_int_t ngx_http_hello_init(ngx_conf_t *cf){
ngx_http_handler_pt *h;
ngx_http_core_main_conf_t *cmcf;
cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);
//在模块内容被解析的时候,会有一个函数链(handlers)被挨个调用,我们把上面那玩意儿
//加到这个handlers里面去就行了。
h = ngx_array_push(&cmcf->phases[NGX_HTTP_CONTENT_PHASE].handlers);
if (h == NULL) {
return NGX_ERROR;
}
//改变函数指针的值
*h = ngx_http_hello_handler;
return NGX_OK;
}
static ngx_http_module_t ngx_http_hello_module_ctx = {
NULL, /* preconfiguration */
ngx_http_hello_init, /* postconfiguration */
NULL, /* create main configuration */
NULL, /* init main configuration */
NULL, /* create server configuration */
NULL, /* merge server configuration */
ngx_http_hello_create_loc_conf, /* create location configuration */
NULL /* merge location configuration */
};
看博客的你心想:“凭借哥180的智商断定这函数是在解析完配置文件被调用的!”,笔者为阁下有
如此高的领悟力深感欣慰!
此配置就是在框架初始化时的八个回调函数。
前戏太长,看博客的你可能心里不太耐烦了,话不多说让咱看看配置文件:
location /test {
hello_string Hello world;
}
咱的目的:访问 ip/test时输出hello world。框架如何解析hello_string配置项的?
static ngx_command_t ngx_http_hello_commands[] = {
{
ngx_string("hello_string"), //模块名称
NGX_HTTP_LOC_CONF|NGX_CONF_NOARGS|NGX_CONF_TAKE1, //location级别内,不带参数,或者带一个参数
ngx_http_hello_string, //解析配置文件的方法
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_hello_loc_conf_t, hello_string),
NULL
},
ngx_null_command
};
我们有了上下文,也有了命令,接下来就要定义模块了,让他们形成漂亮的3p:
ngx_module_t ngx_http_hello_module = {
NGX_MODULE_V1,
&ngx_http_hello_module_ctx, /* module context */
ngx_http_hello_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
};
哥尼玛日了狗了,两函数差点没看懂,搞配置文件的俩函数(差点因为这俩函数b都装不成了)
咱输出Hello world不太需要处理配置文件,后面详解配置模块:
static void *ngx_http_hello_create_loc_conf(ngx_conf_t *cf)
{
//为配置文件信息分配存储结构,没有这玩意儿可能会段错误哟亲
ngx_http_hello_loc_conf_t* local_conf = NULL;
local_conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_hello_loc_conf_t));
if (local_conf == NULL)
{
return NULL;
}
ngx_str_null(&local_conf->hello_string);
//返回分配好的结构
return local_conf;
}
static char *
ngx_http_hello_string(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
ngx_http_hello_loc_conf_t* local_conf;
//conf就里就是配置块的信息。
local_conf = conf;
//获取字符串类型的参数
char* rv = ngx_conf_set_str_slot(cf, cmd, conf);
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "hello_string:%s", local_conf->hello_string.data);
return rv;
}
好了,可以编译我们的模块了
$mkdir nginx-module $cd nginx-module $touch ngx_http_mytest_module.c config
福利,完整的.c文件代码:
#include <ngx_config.h>
#include <ngx_core.h>
#include <ngx_http.h>
typedef struct
{
ngx_str_t hello_string;
}ngx_http_hello_loc_conf_t;
static ngx_int_t ngx_http_hello_init(ngx_conf_t *cf);
static void *ngx_http_hello_create_loc_conf(ngx_conf_t *cf);
static char *ngx_http_hello_string(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf);
static ngx_command_t ngx_http_hello_commands[] = {
{
ngx_string("hello_string"),
NGX_HTTP_LOC_CONF|NGX_CONF_NOARGS|NGX_CONF_TAKE1,
ngx_http_hello_string,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_hello_loc_conf_t, hello_string),
NULL
},
ngx_null_command
};
static ngx_http_module_t ngx_http_hello_module_ctx = {
NULL, /* preconfiguration */
ngx_http_hello_init, /* postconfiguration */
NULL, /* create main configuration */
NULL, /* init main configuration */
NULL, /* create server configuration */
NULL, /* merge server configuration */
ngx_http_hello_create_loc_conf, /* create location configuration */
NULL /* merge location configuration */
};
ngx_module_t ngx_http_hello_module = {
NGX_MODULE_V1,
&ngx_http_hello_module_ctx, /* module context */
ngx_http_hello_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_handler(ngx_http_request_t *r)
{
ngx_http_discard_request_body(r);
ngx_str_t response = ngx_string("Hello world");
ngx_buf_t* b;
b = ngx_create_temp_buf(r->pool, response.len);
ngx_memcpy(b->pos, response.data, response.len);
b->last = b->pos + response.len;
b->last_buf = 1;
r->headers_out.status = NGX_HTTP_OK;
r->headers_out.content_length_n = response.len;
ngx_http_send_header(r);
ngx_chain_t out;
out.buf = b;
out.next = NULL;
return ngx_http_output_filter(r, &out);
}
static void *ngx_http_hello_create_loc_conf(ngx_conf_t *cf)
{
ngx_http_hello_loc_conf_t* local_conf = NULL;
local_conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_hello_loc_conf_t));
if (local_conf == NULL)
{
return NULL;
}
ngx_str_null(&local_conf->hello_string);
return local_conf;
}
static char *
ngx_http_hello_string(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
ngx_http_hello_loc_conf_t* local_conf;
local_conf = conf;
char* rv = ngx_conf_set_str_slot(cf, cmd, conf);
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "hello_string:%s", local_conf->hello_string.data);
return rv;
}
static ngx_int_t
ngx_http_hello_init(ngx_conf_t *cf)
{
ngx_http_handler_pt *h;
ngx_http_core_main_conf_t *cmcf;
cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);
h = ngx_array_push(&cmcf->phases[NGX_HTTP_CONTENT_PHASE].handlers);
if (h == NULL) {
return NGX_ERROR;
}
*h = ngx_http_hello_handler;
return NGX_OK;
}
哥复制粘贴这么累,你不点个赞对的起我?
config文件,模块的名称,源文件名:
ngx_add_name=ngx_http_hello_module
HTTP_MODULES="$HTTP_MODULES ngx_http_hello_module"
NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/ngx_http_mytest_module.c"
找到你nginx源码的目录(你不要傻不拉唧的真写yourpath):
$./configure --add-module=yourpath/nginx-module/ && make && make install
一般安装目录在/usr/local/nginx下面
修改配置文件:
$vim /usr/local/nginx/conf/nginx.conf location /test{ hello_string sb; }
运行nginx:
$/usr/local/nginx/sbin/nginx
浏览器访问:
另:
在gdb调试handler的时候,要去调试worker进程
$ps -aux|grep nginx $gdb ...)attach nginx_worker_pid ...)b XXX_handler ...)c //发送请求后执行c命令
转载于:https://blog.51cto.com/fangnux/1679682