elloWorld 是一个典型的 location 模块。什么是 location 模块?在 Nginx 中,根据作用域,有 main 模块、server 模块、location 模块。

1 模块定义

在 HelloWorld 模块中有一个 ngx_http_hello_world_module 变量,用于定义模块。它是 ngx_module_t 类型。ngx_module_t 是 ngx_module_s 的别名,其定义如下:

struct 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; // Nginx模块版本 void *ctx; // 上下文定义的地址
ngx_command_t *commands; // 命令定义地址
ngx_uint_t type; // 模块类型 ngx_int_t (*init_master)(ngx_log_t *log); // 初始化 master 时执行 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); // 退出 master 时执行 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;
};

在 HelloWorld 例子中:

// Structure for the HelloWorld module, the most important thing
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
};

1.1 NGX_MODULE_V1

看它的定义你就知道,它是用来填充前 7 个 fields 的。

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

1.2 模块类型

我们的模块是 HTTP 模块,还可以开发 CORE 模块,或者 CONF 模块等等。

// ngx_http_config.h
#define NGX_HTTP_MODULE 0x50545448 /* "HTTP" */ // ngx_conf_file.h
#define NGX_CORE_MODULE 0x45524F43 /* "CORE" */
#define NGX_CONF_MODULE 0x464E4F43 /* "CONF" */

1.3 NGX_MODULE_V1_PADDING

这个还是用来填充字段的,或者叫 padding、补白。

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

2 命令定义

命令定义用到如下数据结构:

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;
};

一般类说会定义很多命令,但是在 HelloWorld 中只有一个命令。

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
};

我们一个一个来看。

2.1 命令名称

name 成员表示命令名称

2.2 命令类型

type 是命令类型。它可以取如下的一个或多个值的“或”:

  • NGX_HTTP_MAIN_CONF:可出现在 http 的主作用域;
  • NGX_HTTP_SRV_CONF:可出现在 http 的 server 作用域;
  • NGX_HTTP_LOC_CONF:可出现在 http 的 location 作用域;
  • NGX_HTTP_UPS_CONF:可出现在 http 的 upstream 作用域;
  • NGX_HTTP_SIF_CONF:which will allow the directive to be included in if statements at the server level. [参考]
  • NGX_CONF_NOARGS:指令没有参数;
  • NGX_CONF_TAKE1:指令读入1个参数;
  • NGX_CONF_TAKE2:指令读入2个参数;
  • NGX_CONF_TAKE7:指令读入7个参数;
  • NGX_CONF_FLAG:指令读入1个布尔型数据(“on”或“off”);
  • NGX_CONF_1MORE:指令至少读入1个参数;
  • NGX_CONF_2MORE:指令至少读入2个参数;

      // ngx_http_config.h
    #define NGX_HTTP_MAIN_CONF 0x02000000
    #define NGX_HTTP_SRV_CONF 0x04000000
    #define NGX_HTTP_LOC_CONF 0x08000000
    #define NGX_HTTP_UPS_CONF 0x10000000
    #define NGX_HTTP_SIF_CONF 0x20000000
    #define NGX_HTTP_LIF_CONF 0x40000000
    #define NGX_HTTP_LMT_CONF 0x80000000 // ngx_conf_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 // ngx_conf_file.h
    #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) // ngx_conf_file.h
    #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

2.3 命令回调函数

这里我们使用的是自己定义的回调函数,还可以使用 Nginx 提供的回调函数,比如:

  • ngx_conf_set_flag_slot:将“on”或者“off”转换成1或0;
  • ngx_conf_set_str_slot:将字符串保存为ngx_str_t;
  • ngx_conf_set_num_slot:解析一个数字并保存为ngx_int_t;
  • ngx_conf_set_size_slot:解析一个数据大小(如:“8k”,“1m”),并保存为size_t;
  • ngx_conf_set_enum_slot:根据枚举定义将字符串翻译成ngx_int_t;
  • ngx_http_set_complex_value_slot:解析一个包含nginx变量的字符串并保存为ngx_http_complex_value_t;

2.4 存储位置

conf 参数它有三个可能的取值,分别如下:

NGX_HTTP_MAIN_CONF_OFFSET
NGX_HTTP_SRV_CONF_OFFSET
NGX_HTTP_LOC_CONF_OFFSET

这可不是随意指定的,如果你的type参数设置了NGX_HTTP_MAIN_CONF,那么这里就要设置为NGX_HTTP_MAIN_CONF_OFFSET。相应的,如果是NGX_HTTP_SRV_CONFNGX_HTTP_LOC_CONF,那么这里就要设置为NGX_HTTP_SRV_CONF_OFFSETNGX_HTTP_LOC_CONF_OFFSET

2.5 offset

表 示数据具体保存在main_conf、srv_conf、loc_conf指向的结构体的哪个位置(offset偏移)。大家可能会问,这个 main_conf等等怎么来的,nginx给我们挖的坑长得是个什么样子,这个我们在介绍 ngx_http_hello_world_module_ctx会说到。

2.6 post

一个补充字段,一般不用的,填入NULL。只是对于某些特殊的处理函数,比如ngx_conf_set_enum_slot,会用这个指针来指向enum定义表。

最后不要忘了加上 ngx_null_command,以表示命令集合定义完成。

3 上下文定义

用到了 HTTP 模块,定义如下:

typedef struct {
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_module_t;

可看到有以下几个部分:

  • Pre configuration
  • Post configuration
  • create main configuration
  • init main configuration
  • create server configuration
  • merge server configuration
  • create location configuration
  • merge location configuration

它们都是函数指针,都可以为 NULL,不过我们的模块里用到的是:

// Structure for the HelloWorld context
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
};

这两个函数会在下一篇文章中介绍。

4 Reference

  1. http://forum.nginx.org/read.php?2,243
  2. http://blog.sina.com.cn/s/blog_7303a1dc0100x70t.html

-

解剖Nginx·模块开发篇(2)ngx_http_hello_world_module 模块基本结构定义的更多相关文章

  1. 解剖Nginx·模块开发篇(1)跑起你的 Hello World 模块!

    1 学习 Nginx 模块开发需要有哪些准备? 需要的预备知识不多,有如下几点: 有过一些 C 语言的编程经历: 知道 Nginx 是干嘛的,并有过编写或改写 Nginx 的配置文件的经历. OK,就 ...

  2. nginx模块开发篇 (阿里著作)

    背景介绍 nginx历史 使用简介 nginx特点介绍 nginx平台初探(100%) 初探nginx架构(100%) nginx基础概念(100%) connection request 基本数据结 ...

  3. 【Nginx】开发一个HTTP过滤模块

    与HTTP处理模块不同.HTTP过滤模块的工作是对发送给用户的HTTP响应做一些加工. server返回的一个响应能够被随意多个HTTP过滤模块以流水线的方式依次处理.HTTP响应分为头部和包体,ng ...

  4. 解剖Nginx·自动脚本篇(5)编译器相关主脚本

    在 Nginx 的自动脚本中,auto/cc目录下的所有脚本都是用于编译器相关配置使用的.Nginx的出色跨平台性(Linux.Darwin.Solaris.Win32 等)就有这些脚本的贡献.该目录 ...

  5. 解剖Nginx·模块开发篇(3)ngx_http_hello_world_module 模块的基本函数实现

    还记得我们定义过一个结构体如下吗? typedef struct { ngx_str_t output_words; } ngx_http_hello_world_loc_conf_t; 它就是 He ...

  6. 解剖Nginx·模块开发篇(5)解读内置非默认模块 ngx_http_stub_status_module

    1 Background ngx_http_stub_status_module 是一个 Nginx 的内置 HTTP 模块,该模块可以提供 Nginx 的状态信息.默认情况下这个模块是不被编译进来的 ...

  7. 解剖Nginx·模块开发篇(4)模块开发中的命名规则和模块加载与运行流程

    1 命名规则 1.1 基本变量 基本变量有三个: ngx_module_t 类型的 ngx_http_foo_bar_module: ngx_command_t 类型的数组 ngx_http_foo_ ...

  8. Nginx模块开发1_明白自定义模块的编译流程

    自定义模块的编译流程 --add-module参数 configure使用--add-module参数指定添加模块目录. config脚本 由--add-module指定的目录保存为$ngx-addo ...

  9. 解剖Nginx·自动脚本篇(3)源码相关变量脚本 auto/sources

    在configure脚本中,运行完auto/options和auto/init脚本后,接下来就运行auto/soures脚本.这个脚本是为编译做准备的. 目录 核心模块 事件模块 OpenSSL 模块 ...

随机推荐

  1. autoconf 添加三方库(libcurl)简单试用

    1. 参考项目 https://github.com/rongfengliang/autoconf-project 2. 项目说明 a. 项目结构 ├── Jenkinsfile # jenkins ...

  2. bower.json 的版本范围

    bower.json 的版本范围 有小伙伴问 ~2.2.0 什么意思. 而且在git 的tags 中没有了 2.2.0 版本,怎么样? 实际上 ~2.2.0 的意思是 >=2.2.0 <2 ...

  3. 搭建基于hyperledger fabric的联盟社区(二) --环境配置

    接下来讲一下在本地测试区块链网络的过程.我要部署的是2peer+1orderer架构,所以需要准备三台虚拟机,为了方便起见可以先把一台配置好,然后复制出剩余两台即可.搭建虚拟机我用的是virtualb ...

  4. Windows Restart Manager 重启管理器

    Restart Manager(以下简称RM)可以减少或避免安装或更新程序所需要的系统重启次数.安装(或更新)过程中需要重启的主要原因是需要更新的某些文件当前正被一些其它程序或服务所使用.RM允许除关 ...

  5. java web 程序---刷新页面次数进一步

    <%@ page language="java" import="java.util.*" pageEncoding="gb2312" ...

  6. 多分类下的ROC曲线和AUC

    本文主要介绍一下多分类下的ROC曲线绘制和AUC计算,并以鸢尾花数据为例,简单用python进行一下说明.如果对ROC和AUC二分类下的概念不是很了解,可以先参考下这篇文章:http://blog.c ...

  7. [转]Jsp 映射

    <servlet> <servlet-name>SimpleJspServlet</servlet-name> <jsp-file>/jsp/simpl ...

  8. 使用Java读取配置文件

    实现起来,相对比较简单,留个备案吧,废话也不多说,请看代码: package com.jd.***.config; import org.junit.*; import java.io.IOExcep ...

  9. Java8函数式接口和Lambda表达式

    两者关系: Lambda表达式就是函数式接口(FunctionalInterface)实现的快捷方式,它相当于函数式接口实现的实例,因为在方法中可以使用Object作为参数,所以把Lambda表达式作 ...

  10. win iso download

    http://rufus.akeo.ie/ window iso download http://win.86tyu.cn/ylmf32win7.html