Nginx使用ngx_int_t封装有符号整型,使用ngx_uint_t封装无符号整型。
在Linux平台下,Nginx对ngx_int_t和ngx_uint_t的定义如下:
typedef intprr_t ngx_int_t; typedef uintprr_t ngx_uint_t;ngx_str_t数据结构
在Nginx的领域中,ngx_str_t结构就是字符串。nginx_str_t的定义如下:
typedef struct {
size_t len;
u_char *data;
} ngx_str_t;
ngx_str_t只有两个成员;
- data指针:只想字符串起始地址;
- len:表示字符串的有效长度;
注意:ngx_str_t的data成员指向的并不是普通的字符串,因为这段字符串未必会以’ ’作为结尾,所以使用时必须根据长度len来使用data成员。
ngx_list_t数据结构ngx_list_t是Nginx封装的链表容器,它在Nginx中使用得很频繁,例如HTTP的头部就是用ngx_list_t来存储的。ngx_list_t的定义如下:
typedef struct ngx_list_part_s ngx_list_t;
struct ngx_list_part_s {
void *elts;
ngx_uint_t nelts;
ngx_list_part_t *next;
};
typedef struct {
ngx_list_part_t *last;
ngx_list_part_t part;
size_t size;
ngx_uint_t nalloc;
ngx_pool_t *pool;
} ngx_list_t;
ngx_list_t描述整个链表,而ngx_list_part_t只描述链表中的一个元素。ngx_list_t不是一个单纯的链表,姑且称它为存储数组的链表,就是每个链表元素ngx_list_part_t又是一个数组,拥有连续的内存,它既依赖于ngx_list_t里的size和nalloc来表示数组的容量,同时又依靠每个ngx_list_part_t成员中的nelts来表示数组当前已使用了多少容量。因此,ngx_list_t是一个链表容器,而链表中的元素又是一个数组。这样设计的好处:
- 链表中存储的元素是灵活的,它可以是任何一种数据结构
- 链表元素需要占用的内存由ngx_list_t管理,它已经通过数组分配好了
- 小块的内存使用链表访问效率是低下的,使用数组通过偏移量来直接访问内存则要高效得多
下面详述每个成员的意义:
ngx_list_t:
- part:链表的首个数组元素。
- last:指向链表的最后一个数组元素。
- size:链表中的每个ngx_list_part_t元素都是一个数组。因为数组存储的是某种类型的数据结构,且ngx_list_t是非常灵活的数据结构,所以它不会限制存储什么样的数据,只是通过size限制每一个数组元素的占用的空间大小,也就是用户要存储的一个数据所占用的字节数必须小于或等于size。
- nalloc:链表的数组元素一旦分配后是不可更改的。nalloc表示每个ngx_list_part_t数组的容量,即最多可存储多少个数据。
- poll:链表中管理内存分配的内存池对象,用户要存放的数据占用的内存都是由pool分配的。
ngx_list_part_t:
- elts:指向数组的其实地址
- nelts:表示数组中已经使用了多少个元素。当然,nelts必须小于ngx_list_t数据结构体中的nalloc。
- next:下一个链表元素ngx_list_part_t的地址。
typedef struct {
ngx_uint_t hash;
ngx_str_t key;
ngx_str_t value;
u_char *lowcase_key;
} ngx_table_elt_t;
可以看到,ngx_table_elt_t就是一个key/value对,ngx_str_t类型的key,value成员分别存储的是名字、值字符串。
- hash:表明ngx_table_elt_t也可以是某个散列表数据结构(ngx_hash_t类型)中的成员。
- ngx_uint_t类型的hash成员可以再ngx_hash_t中更快地找到相同key的ngx_table_elt_t数据。
- lowcase_key:指向的是全小写的key字符串。
显而易见,ngx_table_elt_t是为HTTP头部“量身定制”的,其中key存储头部名称,value存储对应的值,lowcase_key是为了忽略HTTP头部名称的大小写,hash用于快速检索头部。
ngx_buf_t数据结构缓冲区ngx_buf_t是Nginx处理大数据的关键数据结构,它既应用于内存数据也应用于磁盘数据。下面来看一下相关代码:
typedef struct ngx_buf_s ngx_buf_t;
typedef void *ngx_buf_tag_t;
struct ngx_buf_s {
u_char *pos;
u_char *last;
off_t file_pos;
off_t file_last;
u_char *start;
u_char *end;
ngx_buf_tag_t tag;
ngx_file_t *file;
ngx_buf_t *shadow;
unsigned temporay:1;
unsigned memory:1;
unsigned mmap:1;
unsigned recycled:1;
unsigned in_file:1;
unsigned flush:1;
unsigned sync:1;
unsigned last_buf:1;
unsigned last_in_chain:1;
unsigned last_shadow:1;
unsigned temp_file:1;
}
ngx_buf_t是一种基本数据结构,本质上它提供的仅仅是一些指针成员和标志位。对于HTTP模块来说,需要注意HTTP框架、事件框架是如何设置和使用pos、last等指针以及如何处理这些标志位的。
ngx_chain_t数据结构ngx_chain_t是与ngx_buf_t配合使用的链表数据结构:
typedef struct nax_chain_s ngx_chain_t;
struct ngx_chain_s {
ngx_buf_t *buf;
ngx_chain_t *next;
}
buf指向当前的ngx_buf_t缓冲区,next则用来指向下一个ngx_chain_t。如果这是最后一个ngx_chain_t,那么必须将next置为NULL。
在向用户发送HTTP包体是,就要传入ngx_chain_t链表对象,注意,如果是最后一个ngx_chain_t,那么必须将next置为NULL,否则永远不会发送成功,而且这个请求将一直不会结束(Nginx框架的要求)。



