NGINX 开发指南

栏目: 服务器 · Nginx · 发布时间: 7年前

内容简介:NGINX 开发指南

简介

  • 代码结构

  • 头文件

  • 整数

  • 常用返回值

  • 错误处理

字符串

  • 概述

  • 格式化

  • 数值转换

  • 正则表达式

时间

容器

  • 数组

  • 列表
  • 队列

  • 红黑树

  • 哈希

内存管理

  • 内存池

  • 共享内存

日志

周期

缓冲

网络

  • 连接

事件

  • 事件

  • I/O 事件

  • 定时器事件

  • 延迟事件

  • 遍历事件

进程

线程

模块

  • 添加新模块

  • 核心模块

  • 配置指令

HTTP

  • 连接

  • 请求

  • 配置

  • 阶段

  • 变量

  • 复杂值

  • 请求重定向

  • 子请求

  • 请求结束

  • 请求体

  • 响应

  • 响应体

  • 响应体过滤

  • 构建过滤模块

  • 缓冲重用

  • 负载均衡

代码布局

  • auto — 构建脚本

  • src

    • unix

    • win32

    • modules — 其他HTTP模块

    • v2 — HTTPv2

    • modules — 事件通知模块:epoll, kqueue, select 等

    • core — 基本类型和函数 — string, array, log, pool 等

    • event — event内核

    • http — HTTP内核模块和通用代码

    • mail — mail模块

    • os — 平台相关代码

    • stream — 流相关模块

每个 nginx 文件都应该在开始的时候包含下面两个文件:

#include <ngx_config.h>
#include <ngx_core.h>

除此之外,HTTP 相关的代码应该包含

#include <ngx_http.h>

邮件相关代码应该包含

#include <ngx_mail.h>

流相关代码应该包含

#include <ngx_stream.h>

整数

一般情况下,nginx代码使用如下两个整数类型: ngx_int_t 和  ngx_uint_t ,分别用typedef定义成了 intptr_t 和  uintptr_t

常用返回值

nginx中的大多数函数使用如下类型的返回值:

  • NGX_OK — 处理成功

  • NGX_ERROR — 处理失败

  • NGX_AGAIN — 处理未完成,函数需要被再次调用

  • NGX_DECLINED — 处理被拒绝,例如相关功能在配置文件中被关闭。不要将此当成错误。

  • NGX_BUSY — 资源不可用

  • NGX_DONE — 处理完成或者在他处继续处理。也可以作为处理成功使用。

  • NGX_ABORT — 函数终止。也可以作为处理出错的返回值。

错误处理

为了获取最近一次系统错误码,nginx提供了ngx_errno宏。该宏被映射到了POSIX平台的errno变量上,而在Windows平台中,则变为对GetLastError()的函数调用。为了获取最近一次socket错误码,nginx提供了ngx_socket_errno宏。同样,在POSIX平台上该宏被映射为errno变量,而在Windows环境中则是对WSAGetLastError()进行调用。考虑到对性能的影响,ngx_errno和ngx_socket_errno不应该被连续访问。如果有连续、频繁访问的需要,则应该将错误码的值存储到类型为ngx_err_t的本地变量中,然后使用本地变量进行访问。如果需要设置错误码,可以使用ngx_set_errno(errno)和ngx_set_socket_errno(errno)这两个宏。

ngx_errno和ngx_socket_errno变量可以在调用日志相关函数ngx_log_error()和ngx_log_debugX()的时候使用,这样具体的错误文本就会被添加到日志输出中。

一个使用ngx_errno的例子:

void
ngx_my_kill(ngx_pid_t pid, ngx_log_t *log, int signo)
{
    ngx_err_t  err;

    if (kill(pid, signo) == -1) {
        err = ngx_errno;

        ngx_log_error(NGX_LOG_ALERT, log, err, "kill(%P, %d) failed", pid, signo);

        if (err == NGX_ESRCH) {
            return 2;
        }

        return 1;
    }

    return 0;
}

字符串

概述

nginx使用无符号的char类型指针来表示C字符串:u_char *。

nginx字符串类型ngx_str_t的定义如下所示:

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

结构体成员len存放字符串的长度,成员data指向字符串本身数据。在ngx_str_t中存放的字符串,对于超出len长度的部分可以是NULL结尾('\0'——译者注),也可以不是。在大多数情况是不以NULL结尾的。然而,在nginx的某些代码中(例如解析配置的时候),ngx_str_t中的字符串是以NULL结尾的吗,这种情况会使得字符串比较变得更加简单,也使得使用系统调用的时候更加容易。

nginx提供了一系列关于字符串处理的函数。它们在src/core/ngx_string.h文件中定义。其中的一部分就是对C库中字符串函数的封装:

  • ngx_strcmp()

  • ngx_strncmp()

  • ngx_strstr()

  • ngx_strlen()

  • ngx_strchr()

  • ngx_memcmp()

  • ngx_memset()

  • ngx_memcpy()

  • ngx_memmove()

还有一些nginx特有的字符串函数:

  • ngx_memzero() 内存清0

  • ngx_cpymem() 和ngx_memcpy()行为类似,不同的是该函数返回的是copy后的最终目的地址,这在需要连续拼接多个字符串的场景下很方便。

  • ngx_movemem() 和ngx_memmove()的行为类似,不同的是该函数返回的是move后的最终目的地址。

  • ngx_strlchr() 在字符串中查找一个特定字符,字符串由两个指针界定。

最后是一些大小写转换和字符串比较的函数:

  • ngx_tolower()

  • ngx_toupper()

  • ngx_strlow()

  • ngx_strcasecmp()

  • ngx_strncasecmp()

格式化

nginx提供了一些格式化字符串的函数。以下这些函数支持nginx特有的类型:

  • ngx_sprintf(buf, fmt, ...)

  • ngx_snprintf(buf, max, fmt, ...)

  • ngx_slpintf(buf, last, fmt, ...)

  • ngx_vslprint(buf, last, fmt, args)

  • ngx_vsnprint(buf, max, fmt, args)

这些函数支持的全部格式化选项定义在src/core/ngx_string.c文件中,以下是其中的一部分:

%O — off_t
%T — time_t
%z — size_t
%i — ngx_int_t
%p — void *
%V — ngx_str_t *
%s — u_char * (null-terminated)
%*s — size_t + u_char *

'u'修饰符将类型指明为无符号,'X'和'x'则将输出转换为16禁止。

例如:

u_char     buf[NGX_INT_T_LEN];
size_t     len;
ngx_int_t  n;

/* set n here */

len = ngx_sprintf(buf, "%ui", n) — buf;

数值转换

nginx实现了若干用于数值转换的函数:

  • ngx_atoi(line, n) — 将一个指定长度的字符串转换为一个正整数,类型为ngx_int_t。出错返回NGX_ERROR。

  • ngx_atosz(line, n) — 同上,转换类型为ssize_t

  • ngx_atoof(line, n) — 同上,转换类型为off_t

  • ngx_atotm(line, n) — 同上,转换类型为time_t

  • ngx_atofp(line, n, point) — 将一个固定长度的定点小数字符串转换为ngx_int_t类型的正整数。转换结果会左移point指定的10进制位数。字符串中的定点小数不能含有多过point参数指定的小数位。出错返回NGX_ERROR。举例:ngx_atofp("10.5", 4, 2) 返回1050

  • ngx_hextoi(line, n) — 将表示16进制正整数的字符串转换为ngx_int_t类型的整数。出错返回NGX_ERROR。

正则表达式

nginx中的正则表达式接口是对PCRE库的封装。相关的头文件是src/core/ngx_regex.h。

要使用正则表达式进行字符串匹配,首先需要对正则表达式进行编译,这通常是在配置解析阶段处理的。需要注意的是,因为PCRE的支持是可选的,因此所有使用正则相关接口的代码都需要用NGX_PCRE括起来:

#if (NGX_PCRE)
ngx_regex_t          *re;
ngx_regex_compile_t   rc;

u_char                errstr[NGX_MAX_CONF_ERRSTR];

ngx_str_t  value = ngx_string("message (\\d\\d\\d).*Codeword is '(?<cw>\\w+)'");

ngx_memzero(&rc, sizeof(ngx_regex_compile_t));

rc.pattern = value;
rc.pool = cf->pool;
rc.err.len = NGX_MAX_CONF_ERRSTR;
rc.err.data = errstr;
/* rc.options are passed as is to pcre_compile() */

if (ngx_regex_compile(&rc) != NGX_OK) {
    ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "%V", &rc.err);
    return NGX_CONF_ERROR;
}

re = rc.regex;
#endif

编译成功之后,结构体ngx_regex_compile_t的captures和named_captures成员分别会被填上正则表达式中全部以及命名捕获的数量。

然后,编译过的正则表达式就可以用来进行字符串匹配:

ngx_int_t  n;
int        captures[(1 + rc.captures) * 3];

ngx_str_t input = ngx_string("This is message 123. Codeword is 'foobar'.");

n = ngx_regex_exec(re, &input, captures, (1 + rc.captures) * 3);
if (n >= 0) {
    /* string matches expression */

} else if (n == NGX_REGEX_NO_MATCHED) {
    /* no match was found */

} else {
    /* some error */
    ngx_log_error(NGX_LOG_ALERT, log, 0, ngx_regex_exec_n " failed: %i", n);
}

ngx_regex_exec()的参数有:编译了的正则表达式re,待匹配的字符串s,可选的用于存放发现的捕获和其大小的整数数组。捕获数组的大小必须是3的倍数,这是PCRE库的API要求的。在上面例子中,该数组的大小是通过总捕获数加上字符串自身来计算得出的。

现在,如果成功匹配,则可以对捕获进行访问:

u_char     *p;
size_t      size;
ngx_str_t   name, value;

/* all captures */
for (i = 0; i < n * 2; i += 2) {
    value.data = input.data + captures[i];
    value.len = captures[i + 1] — captures[i];
}

/* accessing named captures */

size = rc.name_size;
p = rc.names;

for (i = 0; i < rc.named_captures; i++, p += size) {

    /* capture name */
    name.data = &p[2];
    name.len = ngx_strlen(name.data);

    n = 2 * ((p[0] << 8) + p[1]);

    /* captured value */
    value.data = &input.data[captures[n]];
    value.len = captures[n + 1] — captures[n];
}

ngx_regex_exec_array()函数接受ngx_regex_elt_t元素的数组(其实就是多个编译好的正则表达式以及对应的名字),一个待匹配字符串以及一个log。该函数会对待匹配字符串逐一应用数组中的正则表达式,直到匹配成功或者无一匹配。存在成功的匹配则返回NGX_OK,否则返回NGX_DECLINED,出错返回NGX_ERROR。


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

iGen

iGen

Jean M. Twenge PhD / Atria Books / 2017-8-22 / USD 27.00

A highly readable and entertaining first look at how today’s members of iGen—the children, teens, and young adults born in the mid-1990s and later—are vastly different from their Millennial predecesso......一起来看看 《iGen》 这本书的介绍吧!

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换