Created
December 15, 2015 09:59
-
-
Save JeOam/fca30ae150a6f8f03475 to your computer and use it in GitHub Desktop.
Nginx 数据结构和方法
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
字符串 => ngx_str_t
typedef struct{
size_t len;
u_char *data;
} ngx_str_t;
比较字符串:ngx_strncmp
// ngx_strncmp 的定义
#define ngx_strncmp(s1,s2,n) strncmp((const char *)s1, (const char *)s2, n)
// ngx_strncmp 的使用,假设 r->method_name 为一个 ngx_int_t 类型的字符串
if(0==ngx_strncmp(r->method_name.data, "PUT", r->method_name.len) ){
//...
}
链表容器 => ngx_list_t
,链表元素 => ngx_list_part_t
typedef struct ngx_list_part_s ngx_list_part_t;
struct ngx_list_part_s { // 本身又相当于一个数组
void *elts; // 指向数组的起始地址
ngx_uint_t nelts; // 表示数组中已经使用了多少个元素
ngx_list_part_t *next; // 下一个链表元素 ngx_list_part_t 的地址
};
typedef struct {
ngx_list_part_t *last; // 指向链表的最后一个数组元素
ngx_list_part_t part; // 链表的首个数组元素
size_t size; // 每一个数组元素的占用的空间大小
ngx_uint_t nalloc; // 每个 ngx_list_part_t 数组的容量,即最多可存储多少个数据
ngx_pool_t *pool; // 链表中管理内存分配的内存池对象。用户要存放的数据占用的内存都是由pool分配的
} ngx_list_t;
ngx_list_t
链表操作:
ngx_list_create
: 创建新的链表ngx_list_init
: 初始化一个已有的链表ngx_list_push
: 添加新的元素
函数定义:
/**
* pool 参数是内存池对象
* n 是每个链表数组可容纳元素的个数(相当于 ngx_list_t 结构中的 nalloc 成员)
* size 是每个元素的大小
* return: 成功则返回新创建的链表地址,如果创建失败,则返回NULL空指针
*/
ngx_list_t *ngx_list_create (ngx_pool_t *pool, ngx_uint_t n ,size_t size);
/**
* 若 ngx_list_init 返回 NGX_OK,则表示初始化成功,若返回 NGX_ERROR,则表示失败。
*/
static ngx_inline ngx_int_t ngx_list_init (ngx_list_t *list, ngx_pool_t *pool, ngx_uint_t n, size_t size);
/**
* 正常情况下,返回的是新分配的元素首地址。如果返回NULL空指针,则表示添加失败。
* 在使用它时通常先调用 ngx_list_push 得到返回的元素地址,再对返回的地址进行赋值。
*/
void *ngx_list_push (ngx_list_t *list);
使用示例:
// 建立一个链表,它存储的元素是 ngx_str_t,其中每个链表数组中存储 4 个元素
ngx_list_t *testlist = ngx_list_create(r->pool, 4, sizeof(ngx_str_t));
if (testlist == NULL) {
return NGX_ERROR;
}
if (NGX_ERROR == ngx_list_init(testlist, r->pool, 4, sizeof(ngx_str_t))) {
return NGX_ERROR
}
ngx_list_part_t *part = ngx_list_push(testlist);
if (str==NULL){
return NGX_ERROR;
}
ngx_str_t *str = part->elts;
str->len = sizeof("Hello world");
str->value = "Hello world";
key/value
对 => ngx_table_elt_t
typedef struct{
ngx_uint_t hash; // 快速检索
ngx_str_t key;
ngx_str_t value;
u_char *lowcase_key; // 全小写的 key 字符串
}ngx_table_elt_t;
缓冲区相关的数据结构:ngx_buf_t
typedef struct ngx_buf_s ngx_buf_t;
typedef void *ngx_buf_tag_t;
struct ngx_buf_s{
/*pos通常是用来告诉使用者本次应该从pos这个位置开始处理内存中的数据, 这样设置是因为同一个ngx_buf_t可能被多次反复处理。当然, pos的含义是由使用它的模块定义的*/
u_char *pos;
/*last通常表示有效的内容到此为止, 注意, pos与last之间的内存是希望nginx处理的内容*/
u_char *last;
/*处理文件时, file_pos与file_last的含义与处理内存时的pos与last相同, file_pos表示将要处理的文件位置, file_last表示截止的文件位置*/
off_t file_pos;
off_t file_last;
//如果ngx_buf_t缓冲区用于内存, 那么start指向这段内存的起始地址
u_char *start;
//与start成员对应, 指向缓冲区内存的末尾
u_char *end;
/*表示当前缓冲区的类型, 例如由哪个模块使用就指向这个模块ngx_module_t变量的地址*/
ngx_buf_tag_t tag;
//引用的文件
ngx_file_t *file;
/*当前缓冲区的影子缓冲区, 该成员很少用到, 仅仅在12.8节描述的使用缓冲区转发上游服务器的响应时才使用了shadow成员, 这是因为Nginx太节约内存了, 分配一块内存并使用ngx_buf_t表示接收到的上游服务器响应后, 在向下游客户端转发时可能会把这块内存存储到文件中, 也可能直接向下游发送, 此时Nginx绝不会重新复制一份内存用于新的目的, 而是再次建立一个ngx_buf_t结构体指向原内存, 这样多个ngx_buf_t结构体指向了同一块内存, 它们之间的关系就通过shadow成员来引用。这种设计过于复杂, 通常不建议使用*/
ngx_buf_t *shadow;
//临时内存标志位, 为1时表示数据在内存中且这段内存可以修改
unsigned temporary:1;
//标志位, 为1时表示数据在内存中且这段内存不可以被修改
unsigned memory:1;
//标志位, 为1时表示这段内存是用mmap系统调用映射过来的, 不可以被修改
unsigned mmap:1;
//标志位, 为1时表示可回收
unsigned recycled:1;
//标志位, 为1时表示这段缓冲区处理的是文件而不是内存
unsigned in_file:1;
//标志位, 为1时表示需要执行flush操作
unsigned flush:1;
/*标志位, 对于操作这块缓冲区时是否使用同步方式, 需谨慎考虑, 这可能会阻塞Nginx进程, Nginx中所有操作几乎都是异步的, 这是它支持高并发的关键。有些框架代码在sync为1时可能会有阻塞的方式进行I/O操作, 它的意义视使用它的Nginx模块而定*/
unsigned sync:1;
/*标志位, 表示是否是最后一块缓冲区, 因为ngx_buf_t可以由ngx_chain_t链表串联起来, 因此, 当last_buf为1时, 表示当前是最后一块待处理的缓冲区*/
unsigned last_buf:1;
//标志位, 表示是否是ngx_chain_t中的最后一块缓冲区
unsigned last_in_chain:1;
/*标志位, 表示是否是最后一个影子缓冲区, 与shadow域配合使用。通常不建议使用它*/
unsigned last_shadow:1;
//标志位, 表示当前缓冲区是否属于临时文件
unsigned temp_file:1;
};
ngx_chain_t
是与 ngx_buf_t
配合使用的链表数据结构
typedef struct ngx_chain_s ngx_chain_t;
struct ngx_chain_s{
ngx_buf_t *buf; // 指向当前的 ngx_buf_t 缓冲区
ngx_chain_t *next; // 指向下一个ngx_chain_t。如果这是最后一个ngx_chain_t,则需要把next置为NULL。
};
在向用户发送 HTTP 包体时,就要传入 ngx_chain_t 链表对象,注意,如果是最后一个 ngx_chain_t,那么必须将 next 置为 NULL,否则永远不会发送成功,而且这个请求将一直不会结束(Nginx框架的要求)。
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
int
=>ngx_int_t
unsigned int
=>ngx_uint_t