nginx模块开发入门

(为了让流程更清晰,我删掉了各种错误处理与返回值判断等等,实际中还是要判断判断滴)


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

浏览器访问:

wKiom1W4hfSxsmyXAABC7-1GqhQ684.jpg

另:

在gdb调试handler的时候,要去调试worker进程

$ps -aux|grep nginx
$gdb
...)attach nginx_worker_pid
...)b XXX_handler   
...)c                           //发送请求后执行c命令


你可能感兴趣的:(nginx,源码学习,模块开发)