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


    1.预读

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

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

    2..基本数据结构

    ngx_buf_t表示一个单块的缓冲区,既可以是内存也可以是文件。它的结构比较复杂可以分成两个部分:缓冲区信息和标志位信息,

    缓冲区:

    1. struct ngx_buf_s {
    2. u_char *pos;
    3. u_char *last;
    4. off_t file_pos;
    5. off_t file_last;
    6. u_char *start; /* start of buffer */
    7. u_char *end; /* end of buffer */
    8. ngx_buf_tag_t tag;
    9. ngx_file_t *file;
    10. ngx_buf_t *shadow;
    11. };

    结构成员

    pos: 内存数据的起始位置

    last: 内存位置的结束位置

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

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

    start:    内存数据的上界

    end:     内存数据的下界

    tag       关联对象

    file       文件对象

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

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

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

    内存布局

     

    标志位信息

    1. /* the buf's content could be changed */
    2. unsigned temporary:1;
    3. /*
    4. * the buf's content is in a memory cache or in a read only memory
    5. * and must not be changed
    6. */
    7. unsigned memory:1;
    8. /* the buf's content is mmap()ed and must not be changed */
    9. unsigned mmap:1;
    10. unsigned recycled:1;
    11. unsigned in_file:1;
    12. unsigned flush:1;
    13. unsigned sync:1;
    14. unsigned last_buf:1;
    15. unsigned last_in_chain:1;
    16. unsigned last_shadow:1;
    17. unsigned temp_file:1;
    18. /* 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个二进制位即可,省时省空间。

    操作函数

    创造

    辅助函数

    1. #define ngx_alloc_buf(pool) ngx_palloc(pool, sizeof(ngx_buf_t))
    2. #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);

    1. ngx_buf_t *
    2. ngx_create_temp_buf(ngx_pool_t *pool, size_t size)
    3. {
    4. ngx_buf_t *b;
    5. b = ngx_calloc_buf(pool);
    6. if (b == NULL) {
    7. return NULL;
    8. }
    9. b->start = ngx_palloc(pool, size);
    10. if (b->start == NULL) {
    11. return NULL;
    12. }
    13. /*
    14. * set by ngx_calloc_buf():
    15. *
    16. * b->file_pos = 0;
    17. * b->file_last = 0;
    18. * b->file = NULL;
    19. * b->shadow = NULL;
    20. * b->tag = 0;
    21. * and flags
    22. */
    23. b->pos = b->start;
    24. b->last = b->start;
    25. b->end = b->last + size;
    26. b->temporary = 1;
    27. return b;
    28. }
    函数返回的ngx_buf_t结构内的成员都已经初始化好了,pos和 last都指向内存块的首位置,表示空缓冲区,而temporary标志位是1。

    判断函数

    1. #define ngx_buf_in_memory(b) (b->temporary || b->memory || b->mmap)
    2. #define ngx_buf_in_memory_only(b) (ngx_buf_in_memory(b) && !b->in_file)
    3. #define ngx_buf_special(b) \
    4. ((b->flush || b->last_buf || b->sync) \
    5. && !ngx_buf_in_memory(b) && !b->in_file)

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

    3 判断是否是特殊区 

    计算内存大小

    1. #define ngx_buf_size(b) \
    2. (ngx_buf_in_memory(b) ? (off_t) (b->last - b->pos): \
    3. (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))
    

  • 相关阅读:
    Linux单节点安装K8S和kubesphere 已验证安装成功
    后端服务之应用预热
    分布式链路追踪--SkyWalking7.0.0+es7.0.0
    (六)Mybatis中接口代理机制及使用
    python判断字符串是否只由字母或数字组成——isalnum函数 的用法及实例
    HDU - 2859 Phalanx(DP)
    计算机网络
    【Flask基础】六,拦截器/请求钩子(全局+模块+资源选择性放行)
    [Git] 系列三随意修改提交记录以及一些技巧
    前端第二课,HTML,alt,title,width/heigh,border,<a>超链接,target,tr,td,th
  • 原文地址:https://blog.csdn.net/qq_62309585/article/details/128061341