nginx 学习笔记(三)基本数据结构

来源:互联网 发布:网络计算机培训 编辑:程序博客网 时间:2024/05/01 07:28

在开发nginx模块之前,要先了解nginx的一些基本的数据结构。。

ngx_int_t

实际上ngx_int_t就是intptr_t的一个typedef
类似的还有ngx_uint_t是uintptr_t的一个typedef

ngx_str_t

ngx_str_t在模块开发时经常用到,代表的就是一个字符串,定义如下:

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

其中len是字符串的长度,data指向字符串的地址,这样的话如果有多个同样的字符串,就可以让data指向同一个地址,节省空间。data不保证字符串后会添加\0,所以在使用ngx_str_t的data成员时候,不要使用strcpy等这些以\0标识结尾的函数。
用来简化ngx_str_t使用的宏有:

  • ngx_string(text) - 初始化ngx_str_t时使用
  • ngx_null_string - 相当于ngx_string(“”)
  • ngx_str_set(str, text) - 设置一个已有的str为text的内容
  • ngx_str_null(str) - 设置一个已有的str为空字符串

ngx_array_t

定义如下

typedef struct ngx_array_s       ngx_array_t;struct ngx_array_s {    void        *elts;    ngx_uint_t   nelts;    size_t       size;    ngx_uint_t   nalloc;    ngx_pool_t  *pool;};

其中成员的含义如下:

  • elts:元素
  • nelts: 当前元素的个数
  • size:每个元素的大小
  • nalloc:元素的上限个数
  • pool:内存池,也就是说需要的内存都是从pool获取的

以及相关函数

/* 在内存池p上分配n个元素,每个元素大小为size,返回构造好的ngx_array_t的地址 */ngx_array_t *ngx_array_create(ngx_pool_t *p, ngx_uint_t n, size_t size);/* 销毁一个ngx_array_t,会由内存池自动释放内存 */void ngx_array_destroy(ngx_array_t *a);/* 在ngx_array_t上添加一个元素,返回元素的地址 */void *ngx_array_push(ngx_array_t *a);/* 在ngx_array_t上添加n个元素,返回元素的地址 */void *ngx_array_push_n(ngx_array_t *a, ngx_uint_t n);/*  *初始化一个已经存在的ngx_array_t *例如 ngx_array_t b; *ngx_array_init(&b, pool, 5, sizeof(int)); */static ngx_inline ngx_int_t ngx_array_init(ngx_array_t *array, ngx_pool_t *pool, ngx_uint_t n, size_t size);

ngx_buf_t

定义:

struct ngx_buf_s {    u_char          *pos;    u_char          *last;    off_t            file_pos;    off_t            file_last;    u_char          *start;         /* start of buffer */    u_char          *end;           /* end of buffer */    ngx_buf_tag_t    tag;    ngx_file_t      *file;    ngx_buf_t       *shadow;    /* the buf's content could be changed */    unsigned         temporary:1;    /*     * the buf's content is in a memory cache or in a read only memory     * and must not be changed     */    unsigned         memory:1;    /* the buf's content is mmap()ed and must not be changed */    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;    /* STUB */ int   num;};

ngx_buf_t代表的是缓冲区,其中各个成员含义如下:

  • pos:缓冲区的起始位置
  • last:缓冲区的终止位置
  • file_pos:缓冲文件时,file_pos代表文件的起始位置
  • file_last:缓冲文件时,file_last代表文件的结束位置
  • start:整个缓冲区的开始位置
  • end:整个缓冲区的结束位置
  • tag:实际上是一个void*类型的指针,使用者可以关联任意的对象上去,只要对使用者有意义。
  • file:处理文件时,代表文件对象
  • shadow:当某一个buf和另一个buf要处理同一个文件或者同一块缓冲区的时候,就不再拷贝一份过来,而是直接指向同一块内存,并且两个buf的shadow指向对方,所以此时释放内存的时候容易造成多次释放,要特别小心
  • temporary:1:为1代表是用户建立的临时内存块,并且内容可以修改
  • memory:1:为1代表数据在内存中,但是不能被修改
  • mmap:1:为1代表数据是放在使用mmap()这个系统调用映射过来的内存中,并且不可以被修改
  • recycled:1:可以被回收的,也就是可以被释放的
  • in_file:1:为1代表处理的是文件
  • flush:1:遇到有flush字段被设置为1的的buf的chain,则该chain的数据即便不是最后结束的数据(last_buf被设置,标志所有要输出的内容都完了),也会进行输出,不会受postpone_output配置的限制,但是会受到发送速率等其他条件的限制。
  • sync:1:这块内存是否用同步操作进行(可能会阻塞nginx)
  • last_buf:1:当这个buf在多个ngx_chain_t内,标识着是否是最后一块buf
  • last_in_chain:1:是否是当前这个ngx_chain_t的最后一块buf,所以last_buf一定是last_in_chain,但是last_in_chain不一定是last_buf,因为可能在另一个chain里这个buf不是那个chain的最后一个buf
  • last_shadow:1:当多个buf互相是shadow的时候,是否是最后一个shadow,在创建一个buf的shadow的时候,通常将新创建的一个buf的last_shadow置为1。
  • temp_file:1:当内存不够的时候,buf的内容需要写到临时文件内,由这个标识位来标识

nginx定义了两个宏来方便的创建buf

#define ngx_alloc_buf(pool)  ngx_palloc(pool, sizeof(ngx_buf_t))#define ngx_calloc_buf(pool) ngx_pcalloc(pool, sizeof(ngx_buf_t))

也可以使用定义好的函数来创建一个临时的内存块,size为内存的大小

ngx_int_t ngx_create_temp_buf(ngx_pool_t *pool, size_t size)

ngx_chain_t

定义如下:

typedef struct ngx_chain_s  ngx_chain_t;struct ngx_chain_s {    ngx_buf_t    *buf;    ngx_chain_t  *next;};

容易看出实际上ngx_chain_t就是ngx_buf_t的一个链表而已。。

可以使用ngx_alloc_chain_link()来创建一个chain,原型如下

ngx_chain_t *ngx_alloc_chain_link(ngx_pool_t *pool);

可以使用ngx_free_chain(pool, cl)宏来释放一个chain的节点

#define ngx_free_chain(pool, cl)                                   \    cl->next = pool->chain;                                        \    pool->chain = cl

容易看出,释放一个chain的节点实际上只是把这个节点放到pool的chain成员上去了,实际上节点并没有被真正的释放,这样的话下次再申请节点的时候可以直接从chain这个成员上拿下来。

原创粉丝点击