博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Nginx学习-编写一个Helloworld模块(1)
阅读量:6047 次
发布时间:2019-06-20

本文共 4560 字,大约阅读时间需要 15 分钟。

hot3.png

    学习Nginx如果直接看代码那肯定会疯掉的,幸好有许多前辈的文章和书籍参考,和在某高人指点下,我开始从一个简单的HTTP模块入手,开始我的学习之旅。

    网上有很多Nginx的Helloworld模块编写教程,我也是参考了其中一个,先实现了一遍,这里贴一下我看的教程,实现之后我也有诸多疑问(完全搞不懂在干什么,反正是实现了...),现在就结合他写的代码和我最近的学习成果,分析一下这些代码究竟干了什么,和Nginx是怎么联系起来的。

    首先,要写http模块就得先取个名字,教程中的模块名称为ngx_http_hello_world_module,与此相对应的数据结构是

ngx_module_t ngx_http_hello_world_module = {    NGX_MODULE_V1,    &ngx_http_hello_world_module_ctx,    ngx_http_hello_world_commands,    NGX_HTTP_MODULE,    NULL,    NULL,    NULL,    NULL,    NULL,            NULL,    NULL,    NGX_MODULE_V1_PADDING};

先看一下ngx_module_t的定义

typedef struct ngx_module_s ngx_module_tstruct ngx_module_s {    ngx_uint_t            ctx_index;    ngx_uint_t            index;    ngx_uint_t            spare0;    ngx_uint_t            spare1;    ngx_uint_t            spare2;    ngx_uint_t            spare3;    ngx_uint_t            version;    void                 *ctx;    ngx_command_t        *commands;    ngx_uint_t            type;    ngx_int_t           (*init_master)(ngx_log_t *log);    ngx_int_t           (*init_module)(ngx_cycle_t *cycle);    ngx_int_t           (*init_process)(ngx_cycle_t *cycle);    ngx_int_t           (*init_thread)(ngx_cycle_t *cycle);    void                (*exit_thread)(ngx_cycle_t *cycle);    void                (*exit_process)(ngx_cycle_t *cycle);    void                (*exit_master)(ngx_cycle_t *cycle);    uintptr_t             spare_hook0;    uintptr_t             spare_hook1;    uintptr_t             spare_hook2;    uintptr_t             spare_hook3;    uintptr_t             spare_hook4;    uintptr_t             spare_hook5;    uintptr_t             spare_hook6;    uintptr_t             spare_hook7;};

可以看到ngx_http_hello_world_module中先对通过NGX_MODULE_V1宏对前7个参数做了初始化

#NGX_MODULE_V1  0,0,0,0,0,0,1

接着将*ctx和*commands分别指向另外定义的2个数据结构,将type定义为NGX_HTTP_MODULE,之后将7个回调函数赋值为NULL,再用NGX_MODULE_V1_PADDING宏对最后8各参数做了初始化

#NGX_MODULE_V1_PADDING  0,0,0,0,0,0,0,0

这里我们需要关心的是*ctx和*commands这2个指针和其对应的数据结构

*ctx:用于指向模块的上下文结构体,由于Nginx中不同模块的功能都各不相同,所以设计为void*类型,在HTTP模块中需要指向ngx_http_module_t结构体。

*commands:用于处理nginx.conf中的配置项。

PS:看到这里可以发现,只要Nginx能够访问到ngx_http_hello_world_module,就能访问到另外2个数据结构了。

现在来看*ctx指向的ngx_http_hello_world_module_ctx

static ngx_http_module_t ngx_http_hello_world_module_ctx = {    NULL,    NULL,    NULL,    NULL,    NULL,    NULL,    ngx_http_hello_world_create_loc_conf,    ngx_http_hello_world_merge_loc_conf};

ngx_http_module_t的定义

typedef struct ngx_http_module_s ngx_http_module_tstruct ngx_http_module_s{    ngx_int_t   (*preconfiguration)(ngx_conf_t *cf);    ngx_int_t   (*postconfiguration)(ngx_conf_t *cf);    void       *(*create_main_conf)(ngx_conf_t *cf);    char       *(*init_main_conf)(ngx_conf_t *cf, void *conf);    void       *(*create_srv_conf)(ngx_conf_t *cf);    char       *(*merge_srv_conf)(ngx_conf_t *cf, void *prev, void *conf);    void       *(*create_loc_conf)(ngx_conf_t *cf);    char       *(*merge_loc_conf)(ngx_conf_t *cf, void *prev, void *conf);} ;

ngx_http_hello_world_module_ctx中只指向了我们定义的2个函数,其中ngx_http_hello_world_create_loc_conf用于创建存储配置项的数据结构,并将该结构的地址返回给Nginx框架,在这个函数中创建了我们为模块自定义的数据结构,

typedef struct {    ngx_str_t output_words;} ngx_http_hello_world_loc_conf_t;

ngx_http_hello_world_merge_loc_conf用于合并srv和loc级别下的同名配置项(意思就是不同级别的配置项中出现了名字相同的配置项以哪个为准,具体标准由模块实现者决定)。这个结构中的函数在NginxHTTP框架启动过程中自动调用。

接着来看*commands指向的ngx_http_hello_world_commands

static ngx_command_t ngx_http_hello_world_commands[] = {    {        ngx_string("hello_world"), // The command name        NGX_HTTP_LOC_CONF | NGX_CONF_TAKE1,        ngx_http_hello_world, // The command handler        NGX_HTTP_LOC_CONF_OFFSET,        offsetof(ngx_http_hello_world_loc_conf_t, output_words),        NULL    },    ngx_null_command};

ngx_command_t的定义

typedef struct ngx_command_s ngx_command_t 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:指定了我们感兴趣的配置项的名称,其中ngx_string是一个宏,用于将字符串转换为ngx_str_t类型数据。

type:表示配置项可以出现的位置和接受参数的个数,set方法用于处理配置项的参数。

conf:用于表示用何级别的方法生成的结构体来保存这个参数。

offset:表示这个配置项在所对应的参数再结构中的偏移位置(offsetof可以直接给出结构体中数据项的位置)。

*post:这个用途就有很多了,这里就不讨论了。

看到这里可以发现只要nginx.conf文件中出现了hello_world配置项就会调用ngx_http_hello_world对配置项进行处理。

我们发现我们定义的ngx_http_hello_world_commands的结构中有2个ngx_command_t结构(ngx_null_command为一个宏,定义一个空的ngx_command_t),这是因为我们的配置项可能有很多,ngx_null_command表示不再需要解析配置项了(我的理解)。

这里我们已经将该模块的几个主要的数据结构分析了一遍,可能还不够深刻,有空再把文中提到的数据结构详细整理一遍。

转载于:https://my.oschina.net/u/1471035/blog/215218

你可能感兴趣的文章
linux在文件中查找指定字符串,然后根据查找结果来做进一步的处理
查看>>
在Oracle中删除所有强制性外键约束
查看>>
【R】R语言使用命令行参数 - [编程技巧(Program Skill)]
查看>>
经典算法题每日演练——第二题 五家共井
查看>>
存储过程中拼接的变量和点的问题
查看>>
ASP.NET那点不为人知的事(一)
查看>>
3.16
查看>>
表单文件上传与文件下载
查看>>
下午考
查看>>
创建字符设备的三种方法
查看>>
走在网页游戏开发的路上(六)
查看>>
nginx 配置的server_name参数(转)
查看>>
Uva592 Island of Logic
查看>>
C++基础代码--20余种数据结构和算法的实现
查看>>
footer固定在页面底部的实现方法总结
查看>>
nginx上传文件大小
查看>>
HDU 2243 考研路茫茫——单词情结(自动机)
查看>>
Dubbo OPS工具——dubbo-admin & dubbo-monitor
查看>>
Dungeon Master ZOJ 1940【优先队列+广搜】
查看>>
Delphi 中的 XMLDocument 类详解(5) - 获取元素内容
查看>>