内容简介: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。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- 网站图标开发指南
- WalletConnect 非权威开发指南
- 2019 简易Web开发指南
- SlimPHP开发指南五:请求
- linux 内核开发指南 - 2 开发流程
- 积木 Sketch 插件进阶开发指南
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。