nginx服务器接收到客户端的http请求头部时,或者nginx发送响应头部给客户端,这些头部字段都会保存到链表数组中。例如:content_type:text/html。内存布局如下图所示。
图:http头部链表
一、链表结构
//链表头结点
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;
//链表数组结点
struct ngx_list_part_s
{
void *elts; //数组首地址
ngx_uint_t nelts; //数组中有效元素个数
ngx_list_part_t *next; //指向下一个链表节点
};
链表所有节点都是通过next指针连接起来。而每一个链表节点的元素是一个数组,数组个数以及每个数组元素大小由链表表头节点中的nalloc与size决定。
二、创建链表
通过ngx_list_create函数可以创建一个链表。可以指定链表数组的大小以及每个数组元素的大小
1、创建一个链表表头
2、为链表第一个节点开辟数组空间、
3、保存数组元素的大小以及数组大小
//创建一个链表头,链表首节点数组有n个元素,每个元素为size大小
ngx_list_t * ngx_list_create(ngx_pool_t *pool, ngx_uint_t n, size_t size)
{
ngx_list_t *list;
//创建一个链表头
list = ngx_palloc(pool, sizeof(ngx_list_t));
if (list == NULL)
{
return NULL;
}
//为链表首节点开辟数组空间
list->part.elts = ngx_palloc(pool, n * size);
if (list->part.elts == NULL)
{
return NULL;
}
//链表元素个数为0,表示没有空间被使用,是一个空链表
list->part.nelts = 0;
list->part.next = NULL;
//将链表连接起来
list->last = &list->part;
//保存数组元素个数以及每个数组元素大小
list->size = size;
list->nalloc = n;
list->pool = pool;
return list;
}
三、初始化链表
初始化一个链表和创建链表的操作基本相同,唯一的差别是初始化链表不需要创建链表头,因为调用者已经创建好了
//初始化一个链表,链表首节点数组有n个元素,每个元素为size大小
static ngx_inline ngx_int_t ngx_list_init(ngx_list_t *list, ngx_pool_t *pool,
ngx_uint_t n, size_t size)
{
//为链表节点开辟数组空间
list->part.elts = ngx_palloc(pool, n * size);
if (list->part.elts == NULL)
{
return NGX_ERROR;
}
//链表元素个数为0,表示没有空间被使用,是一个空链表
list->part.nelts = 0;
list->part.next = NULL;
//将链表连接起来
list->last = &list->part;
//保存数组元素个数以及每个数组元素大小
list->size = size;
list->nalloc = n;
list->pool = pool;
return NGX_OK;
}
四、获取链表节点
如果想要从链表中获取一个元素,则需要使用ngx_list_push函数。函数的返回值就是数组元素,得到这个元素后,就可以对这个元素进行赋值了。
这个跟我们平时使用的链表过程有点不一样。通常我们都是创建一个链表节点,然后对链表节点进行赋值,之后才把链表节点插入到链表中。
而nginx是预先开辟了链表数组节点,要使用时直接获取就可以了。
//从链表尾节点数组中获取一个元素;
//如果链表没有空间了,则创建一个链表数组节点,并插入到链表末尾
//返回值: 链表数组元素
void * ngx_list_push(ngx_list_t *l)
{
void *elt;
ngx_list_part_t *last;
last = l->last;
//链表没有空间了,则重新创建一个链表数组节点
if (last->nelts == l->nalloc)
{
//创建链表节点
last = ngx_palloc(l->pool, sizeof(ngx_list_part_t));
if (last == NULL)
{
return NULL;
}
//开辟数组空间
last->elts = ngx_palloc(l->pool, l->nalloc * l->size);
if (last->elts == NULL)
{
return NULL;
}
last->nelts = 0;
last->next = NULL;
//串接链表,尾插法
l->last->next = last;
l->last = last;
}
//从数组中获取一个元素
elt = (char *) last->elts + l->size * last->nelts;
//更新数组元素的使用个数
last->nelts++;
return elt;
}
最终,链表可能的内存布局如下:
图:链表数组内存布局