Nginx源码分析–单个缓冲区

追求适度,才能走向成功;人在顶峰,迈步就是下坡;身在低谷,抬足既是登高;弦,绷得太紧会断;人,思虑过度会疯;水至清无鱼,人至真无友,山至高无树;适度,不是中庸,而是一种明智的生活态度。

导读:本篇文章讲解 Nginx源码分析–单个缓冲区,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com,来源:原文

1.预读

作为web服务器,Nginx要频繁地收发处理大量的数据,这些数据有时是连续的内存块,有时是多个分散内存块,甚至有时数据过大,内存无法存放,只能保存成磁盘文件。

作为web服务器,Nginx要频繁地收发处理大量的数据,这些数据有时是连续的内存块,有时是多个分散内存块,甚至有时数据过大,内存无法存放,只能保存成磁盘文件。

2..基本数据结构

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;


  
};

结构成员

pos: 内存数据的起始位置

last: 内存位置的结束位置

file_pos: 文件数据的起始偏移量

file_last:文件数据的结束偏移量

start:    内存数据的上界

end:     内存数据的下界

tag       关联对象

file       文件对象

因为Nginx里的缓冲数据可能在内存或者磁盘文件中,所以ngx_buf_t使用pos/lastl file_pos/file_last来指定数据在内存或者文件中的具体位置,究竞数据是在哪里则要由后面的标志位信息来确定

start 和 end 两个成员变量标记了数据所在内存块的边界,如果内存块是可以修改的,那么在操作时必须参考这两个成员防止越界。

tag是一个比较特殊的成员,它的类型是void*,用户可以关联任意数据,在代码中任意解释,通常它指向的是使用该缓冲区的对象。
 

内存布局

Nginx源码分析--单个缓冲区

 

标志位信息

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

结构成员: 

temporary                   内存块临时数据       可以修改

memory                      内存块数据               不可以修改

mmap                          内存映射数据          不许修改

in_file                           缓冲区在文件里面

flush                            要求立马Nginx 立即输出本缓冲区

sync                            要求Nginx同步操作本缓冲区

last_buf                       最后一块缓冲区

last_in_chain               链里最后一块缓冲区

temp_file                      缓冲区在临时文件里

这些标志位的含义都比较好理解,但last_buf和last_in_chain存在一点小差异;前者是整个处理过程中的最后一块缓冲区,标志着TCP/HTTP请求处理的结束;而后者是当前数据块链(ngx_chain_t)里的最后一块,之后可能还会有数据需要处理。

从ngx_buf_t的定义可以看到,一个有数据的缓冲区不是在内存里,就是在文件里,所以内存标志位成员变量(temporary/memory/mmap)和文件标志成员变量(in_file/temp_file)不能全为0,否则Nginx 会认为这是个特殊( special)或无效的缓冲区。

如果缓冲区既不在内存也不在文件里,那么它就不含有有效数据,只起到控制作用
,例如
刷新(
flush
)或者同步(
sync

复习一下

采用位域:

位域是指信息在存储时,并不需要占用一个完整的字节, 而只需占几个或一个二进制位。例如在存放一个开关量时,只有0和1 两种状态, 用一位二进位即可。为了节省存储空间,并使处理简便,C语言又提供了一种数据结构,称为”位域”或”位段”。所谓”位域”是把一个字节中的二进位划分为几 个不同的区域, 并说明每个区域的位数。每个域有一个域名,允许在程序中按域名进行操作。 这样就可以把几个不同的对象用一个字节的二进制位域来表示。

使用位域的好处是:
1.有些信息在存储时,并不需要占用一个完整的字节, 而只需占几个或一个二进制位。例如在存放一个开关量时,只有0和1 两种状态, 用一位二进位即可。这样节省存储空间,而且处理简便。 这样就可以把几个不同的对象用一个字节的二进制位域来表示。
2.可以很方便的利用位域把一个变量给按位分解。比如只需要4个大小在0到3的随即数,就可以只rand()一次,然后每个位域取2个二进制位即可,省时省空间。

操作函数

创造

辅助函数

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

ngx_buf_t *ngx_create_temp_buf(ngx_pool_t *pool, size_t size);

ngx_buf_t *
ngx_create_temp_buf(ngx_pool_t *pool, size_t size)

{
    ngx_buf_t *b;

    b = ngx_calloc_buf(pool);
    if (b == NULL) {
        return NULL;
    }

    b->start = ngx_palloc(pool, size);
    if (b->start == NULL) {
        return NULL;
    }

    /*
     * set by ngx_calloc_buf():
     *
     *     b->file_pos = 0;
     *     b->file_last = 0;
     *     b->file = NULL;
     *     b->shadow = NULL;
     *     b->tag = 0;
     *     and flags
     */

    b->pos = b->start;
    b->last = b->start;
    b->end = b->last + size;
    b->temporary = 1;

    return b;
}
函数返回的ngx_buf_t结构内的成员都已经初始化好了,pos和 last都指向内存块的首位置,表示空缓冲区,而temporary标志位是1。

判断函数

#define ngx_buf_in_memory(b)        (b->temporary || b->memory || b->mmap)
#define ngx_buf_in_memory_only(b)   (ngx_buf_in_memory(b) && !b->in_file)

#define ngx_buf_special(b)                                                   \
    ((b->flush || b->last_buf || b->sync)                                    \
     && !ngx_buf_in_memory(b) && !b->in_file)

1 2函数是判断数据在内存里 采用或运算!!1

3 判断是否是特殊区 

计算内存大小

#define ngx_buf_size(b)                                                      \
    (ngx_buf_in_memory(b) ? (off_t) (b->last - b->pos):                      \
                            (b->file_last - b->file_pos))

1.在内存里面就计算整个内存

2.文件里面就计算文件

拷贝内存(core/ngx_string.h)

拷贝内存数据时我们可以直接使用标准c函数memcpy(),但Nginx自定义了一个函数ngx_cpymem,接口与memcpy()相同,不过它返回的是拷贝数据后的终点位置,在连续夏制多段数据时很方便:

#define ngx_cpymem(dst, src, n)   (((u_char *) ngx_memcpy(dst, src, n)) + (n))

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/129630.html

(0)
飞熊的头像飞熊bm

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!