Nginx学习笔记(三):封装的数据结构

前言

不能保证每天都有时间学这个,毕竟其他方面还有很多的事情需要做,但一定会利用好时间,充实自己。另外,大概扫了下Nginx自己封装的数据结构类型,确实还是蛮多的。所以,暂时打算学一点,更新一点。这一篇也主要是为自己开发一个简单HTTP模块做准备。

封装的数据结构

Nginx为了做到跨平台,追求极致高效,自身定义、封装了一些数据结构。就我个人来说,无论是对这一类统一的数据结构的封装风格,还是其中的封装技巧(尽可能地少占用内存),都是非常喜欢,大赞一个。

1)整型 <ngx_config.h>

typedef intptr_t        ngx_int_t;

typedef uintptr_t      ngx_uint_t;

C99 标准定义了 intptr_t 和 uintptr_t 类型是给一个可以持有一个指针值的整型变量。

2)字符串型 <ngx_string.h>

typedef struct {

    size_t      len;  // 指向字符串首字符地址

    u_char    *data; // 字符串长度

} ngx_str_t;

可以看出,这里基本没有'\0'什么事了。这种封装的优点:1,减少计算字符串长度次数,可以直接用;2,可以重复引用一段字符串内存,长度表示结束。这样,不用对一段字符串再copy一份自己的副本,因为data指针可以指向任何字符串地址,这样可以减少不必要的内存分配与拷贝。也因为这个特性,Nginx中必须谨慎对一段字符串做出修改;另外,任何试图将ngx_str_t的data成员当作字符串来使用,都可能导致内存越界!

因为不存在‘\0’,Nginx专门提供自己有关ngx_str_t的操作的API。简单笔记:

// 以{...}括住,只适用于字符串赋值初始化,计算str长度为sizeof关键字,因此str为字符串常量!     

#define ngx_string(str)    { sizeof(str) - 1, (u_char *) str }

#define ngx_null_string    { 0, NULL }

// 字符串赋值,text为字符串常量!因为是两行代码,在if/for/while等语句中单独使用需要用花括号括起来!

#define ngx_str_set(str, text)                                              \

    (str)->len = sizeof(text) - 1; (str)->data = (u_char *) text

#define ngx_str_null(str)  (str)->len = 0; (str)->data = NULL 

另外Nginx简单封装了glibc的字符串操作API,具体见ngx_string.h。   

3)链表容器 <ngx_list.h>

/* 描述链表的一个结点,此节点实际上是一个数组,拥有一段连续内存 */

typedef struct ngx_list_part_s  ngx_list_part_t;

struct ngx_list_part_s {

    void            *elts;  // 指向数组起始地址

    ngx_uint_t        nelts;  // 表示数组中已经使用多少个元素,其值 <= ngx_list_t中的nalloc

    ngx_list_part_t  *next;  // 下一个链表节点

};

/* 描述整个链表 */

typedef struct {

    ngx_list_part_t  *last;  // 链表尾节点

    ngx_list_part_t  part;  // 链表首节点

    size_t            size;  // 链表的每一个节点实质上是一个数组,但数组元素的类型是不确定的,由size表示每一个数组元素能够存储的最大值

    ngx_uint_t        nalloc; // 表示每一个ngx_list_part_t节点的容量

    ngx_pool_t      *pool;  // 链表中管理内存分配的内存池对象

} ngx_list_t; 

给出书中简图,一种可能的ngx_list_t链表的内存分布结构。

对于链表,Nginx也提供了一组接口:

ngx_list_create接口用于创建新的链表;

ngx_list_init接口初始化一个已有链表;

ngx_list_push接口用于添加新元素。具体情况详见<ngx_list.c>。

4)动态数组容器 <ngx_array.h>

typedef struct {

    void        *elts;  // 指向数组起始地址

    ngx_uint_t  nelts;  // 表示数组中已经使用多少个元素,其值 <= ngx_list_t中的nalloc

    size_t      size;  // 一个数组元素能够存储的最大值

    ngx_uint_t  nalloc; // 当nelts增长到达nalloc 时,如果再往此数组中存储元素,则会引发数组的扩容。

            // 数组的容量将会扩展到原有容量的2倍大小。实际上是分配新的一块内存,

            // 新的一块内存的大小是原有内存大小的2倍。原有的数据会被拷贝到新的一块内存中。

    ngx_pool_t  *pool;  // 管理内存分配的内存池对象

} ngx_array_t;

基本上跟链表容器的节点元素一致,接口也类似,具体详情见<ngx_array.c>。

ngx_array_t容器具备以下三个优点:

访问速度快;

允许元素个数具备不确定性;

负责元素占用内存的分配,这些内存将由内存池统一管理;

画上书中图描述下此结构体及使用方法:

5)缓冲区 <ngx_buf.h>

缓冲区ngx_buf_t是Nginx处理大数据的关键数据结构,它既应用于内存数据也应用于磁盘数据。

typedef struct ngx_buf_s  ngx_buf_t;

typedef void *            ngx_buf_tag_t;

struct ngx_buf_s {

    /* 表示从此为止开始处理内存数据,同一个ngx_buf_t可能被多次反复处理 */

    u_char          *pos;


    /* Nginx有效处理的内存结束地址 */

    u_char          *last;


    /* 处理文件时,含义与pos、last相同 */

    off_t            file_pos;

    off_t            file_last;

    /* 如果ngx_buf_t缓冲区用于内存,这个则指向buf起始地址与尾地址...那上面两字段毛意思,混乱中... */

    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 */

    /* 源码中有英文注释,翻译为中文...

    * 以下均为标志位,且其值置1的意义

    */

    /* 临时内存标志位,表示数据在内存中,可修改 */

    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 */

    /* 表示内存是用mmap系统调用映射过来,不可被修改 */

    unsigned        mmap:1;

/* 表示可回收 */

    unsigned        recycled:1;


    /* buf缓冲区处理的是文件,不是内存 */

    unsigned        in_file:1;


    /* 需要执行flush操作 */

    unsigned        flush:1;


    /* 使用同步方式(可能阻塞Nginx进程,谨慎使用) */

    unsigned        sync:1;


    /* ngx_buf_t可由ngx_chain_t串联,此标志位表示当前是最后一块待处理的缓冲区 */

    unsigned        last_buf:1;


    /* 表示是ngx_chain_t中最后一块缓冲区 */

    unsigned        last_in_chain:1;

/* 配合影子缓冲区使用,表示最后一个影子缓冲区 */

    unsigned        last_shadow:1;


    /* 表示当亲缓冲区属于临时文件 */

    unsigned        temp_file:1;

    /* STUB */ int  num;

};

ngx_buf_t是一种基本的数据结构,本质上提供的仅仅是一些指针成员和标志位。如果我们自定义一个ngx_buf_t结构,则应该根据业务需求自行定义。

5)缓冲区链表 <ngx_buf.h>

typedef struct ngx_chain_s      ngx_chain_t;    <ngx_core.h>

struct ngx_chain_s {                            <ngx_buf.h>

    ngx_buf_t    *buf;  // 指向当前缓冲区

    ngx_chain_t  *next; // 指向下一个,如果是最后一个ngx_chain_t,必须置NULL

};

这个是与ngx_buf_t配合使用的链表结构。摘下博文《Nginx模块开发入门》简图:

总结

暂时没法总结。。还没体会这些数据的好处。对那个str_list_t的设计,比较喜欢。

主要参考

《深入理解Nginx》

《Nginx从入门到精通》

《Nginx模块开发入门》

---------------------

作者:时间文盲

来源:CSDN

原文:https://blog.csdn.net/fzy0201/article/details/17512119

版权声明:本文为博主原创文章,转载请附上博文链接!

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,734评论 6 505
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,931评论 3 394
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,133评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,532评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,585评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,462评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,262评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,153评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,587评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,792评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,919评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,635评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,237评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,855评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,983评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,048评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,864评论 2 354

推荐阅读更多精彩内容