zoukankan      html  css  js  c++  java
  • nginx源码解析之常用数据结构

      1、基础数据结构(src/core目录)

      1)ngx_list_t(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_part_t *next;  // 下一个链表元素ngx_list_part_t的地址
    };
    
    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_create():创建新的链表。

      ngx_list_init():初始化一个已有的链表。返回NGX_OK表示成功,返回NGX_ERROR表示失败。

      ngx_list_push():添加新的元素。正常情况下返回新分配的元素的首地址,若失败则返回NULL

      没有遍历链表的接口。

      2)ngx_buf_t(ngx_buf.h)

    typedef void *ngx_buf_tag_t;
    typedef struct ngx_buf_s ngx_buf_t;
    struct ngx_buf_s {
        u_char *pos;  // 通常表示本次应该从哪个位置开始处理内存中的数据
        u_char *last;  // 通常表示有效的内容到此为止
        off_t file_pos;  // 处理文件时,其含义与处理内存时的pos相同
        off_t file_last;  // 处理文件时,其含义与处理内存时的last相同
    
        u_char *start;  // ngx_buf_t用于内存时,该字段指向这段内存的起始地址
        u_char *end;  // 与start对应,指向缓冲区内存的末尾
        ngx_buf_tag_t tag;  // 表示当前缓冲区的类型,如由哪个模块使用就指向该模块ngx_module_t变量的地址
        ngx_file_t *file;  // 引用的文件
        ngx_buf_t *shadow;  // 当前缓冲区的影子缓冲区,很少使用
    
        unsigned temporary:1;  // 临时内存标志,1表示数据在内存中且这段内存可修改
        unsigned memory:1;  // 1表示数据在内存中且这段内存不可以被修改
        unsigned mmap:1;  // 1表示这段内存是用mmap映射过来的,不可以被修改
    
        unsigned recycled:1;  // 1表示可回收
        unsigned in_file:1;  // 1表示这段缓冲区处理的是文件而不是内存
        unsigned flush:1;  // 1表示需要执行flush操作
        unsigned sync:1;  // 操作这块缓冲区时是否使用同步方式(可能阻塞nginx进程)。nginx中所有操作几乎都是异步的,这是它支持高并发的关键
        unsigned last_buf:1;  // 是否是最后一块缓冲区(如由ngx_chain_t串联起来时)
        unsigned last_in_chain:1;  // 是否是ngx_chain_t中的最后一块缓冲区
    
        unsigned last_shadow:1;  // 是否是最后一个影子缓冲区,与shadow字段配合使用
        unsigned temp_file:1;  // 当前缓冲区是否属于临时文件
    
        /* STUB */ int num;
    };

      3)ngx_table_elt_t(ngx_hash.h)

    typedef struct {
        ngx_uint_t hash;  // 可用于在ngx_hash_t中更快地找到相同key的ngx_table_elt_t
        ngx_str_t key;  // 应用:如存储HTTP头部名称
        ngx_str_t value;  // 应用:如存储HTTP头部名称对应的值
        u_char *lowcase_key;  // 指向全小写的key。应用:如忽略HTTP头部名称大小写
    } ngx_table_elt_t;

      4)ngx_command_t(ngx_conf_file.h):定义了一个配置项。

    typedef struct ngx_command_s ngx_command_t;
    struct ngx_command_s {
        ngx_str_t name;  // 配置项名称
        ngx_uint_t type;  // 配置项类型,决定了配置项可以在哪些块中出现,以及可以携带的参数类型和个数等
        /* 出现name配置项后,调用该函数处理配置项的参数set既可以自定义,也可以使用nginx预设的14个函数
    如ngx_conf_set_flag_slot()(配置项参数为on/off且使用ngx_flag_t变量保存配置项参数时)、ngx_conf_set_str_slot()
    */ char *(*set)(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
    /* 对于HTTP模块,conf是必须设置的。可取值:
    NGX_HTTP_MAIN_CONF_OFFSET:使用ngx_http_module_t结构的create_main_conf()产生的结构体来存储解析出的配置项参数。
    NGX_HTTP_SRV_CONF_OFFSET:使用create_srv_conf()产生的结构体来存储解析出的配置项参数。
    NGX_HTTP_LOC_CONF_OFFSET:使用create_loc_conf()产生的结构体来存储解析出的配置项参数。 */
    ngx_uint_t conf;
    // 在配置文件中的偏移量
    /* 当前配置项在整个存储配置项的结构体中的偏移位置(字节)。可借助stddef.h的offsetof宏求得 */
    ngx_uint_t offset; // 需要与conf配合使用
    /* 若自定义了配置项的回调函数,则post的用途完全由用户定义;若使用的是nginx预设的配置项解析函数,则需要根据这些函数决定post的使用方式:
    如对于ngx_conf_set_flag_slot(),可设置为NULL,或指向ngx_conf_post_t结构。该结构包含一个函数指针,表示在解析完配置项后回调这个函数。
    对于ngx_conf_set_enum_slot(),应把post指向ngx_conf_enum_t数组(规定了当前配置项参数的取值范围)。
    对于ngx_conf_set_bufs_slot()post无任何用处。 */
    void *post; };

      5)ngx_module_t(ngx_module.h)

    typedef struct ngx_module_s ngx_module_t;
    struct ngx_module_s {
    /* ctx_index/index/spare0~spare3/version可以使用该宏来赋值 */
    #define NGX_MODULE_V1 0, 0, 0, 0, 0, 0, 1
    
        /* 当前模块在某一类(type)模块中的序号。通常由管理这类模块的一个核心模块设置(如HTTP模块由ngx_http_module设置)。
    nginx的模块化设计非常依赖于各个模块的顺序,它们既用于表达优先级,也用于表明每个模块的位置,借以帮助nginx框架快速获得某个模块的数据
    */ ngx_uint_t ctx_index; ngx_uint_t index; // 当前模块在ngx_modules数组中的序号 ngx_uint_t spare0; // spare0~spare3为保留字段 // ... ngx_uint_t version; // 模块版本,便于将来的扩展。目前只有一种,默认为1 void *ctx; // 指向一类模块的上下文结构体(公共接口),如HTTP模块的ctx需要指向ngx_http_module_t结构体 ngx_command_t *commands; // 处理nginx.conf中的配置项 ngx_uint_t type; // 模块类型,如HTTP模块类型为NGX_HTTP_MODULE ngx_int_t (*init_master)(ngx_log_t *log); // 目前不会被调用,可设置为NULL ngx_int_t (*init_module)(ngx_cycle_t *cycle); // 在初始化所有模块时被调用。在master/worker模式下,这个阶段将在启动worker子进程前完成 /* 在正常服务前被调用。在master/worker模式下,多个worker子进程已经产生,在每个worker进程的初始化过程会调用所有模块的init_process() */ ngx_int_t (*init_process)(ngx_cycle_t *cycle); ngx_int_t (*init_thread)(ngx_cycle_t *cycle); // nginx暂不支持多线程,故设为NULL void (*exit_thread)(ngx_cycle_t *cycle); // 同上 void (*exit_process)(ngx_cycle_t *cycle); // 在服务停止前调用。在master/worker模式下,worker进程会在退出前调用它 void (*exit_master)(ngx_cycle_t *cycle); // 在master进程退出前被调用 uintptr_t spare_hook0; // spare_hook0~spare_hook7为保留字段,可以使用NGX_MODULE_V1_PADDING宏来赋值 // ... };

      2、HTTP相关数据结构(src/http目录)

      1)ngx_http_headers_in_t(ngx_http_request.h)

    typedef struct {
        ngx_list_t headers;  // 包含所有解析过的HTTP头部
        /* 以下ngx_table_elt_t *类型成员实际上都指向了headers中的相应成员 */
        ngx_table_elt_t *host;
        ngx_table_elt_t *connection;
        // ... ...
        ngx_array_t cookies;
        ngx_str_t server;  // server名称
        // ...
        /* HTTP连接类型(0/NGX_HTTP_CONNECTION_CLOSE/NGX_HTTP_CONNECTION_KEEP_ALIVE) */
        unsigned connection_type:2;
        /* 以下标志位用于判断浏览器类型(根据浏览器传来的useragent头部设置) */
        unsigned chunked:1;
        unsigned msie:1;
        unsigned msie6:1;
        unsigned opera:1;
        unsigned gecko:1;
        unsigned chrome:1;
        unsigned safari:1;
        unsigned konqueror:1;
    } ngx_http_headers_in_t;

      2)ngx_http_headers_out_t(ngx_http_request.h)

    typedef struct {
        ngx_list_t headers;  // 待发送的HTTP(响应)头部链表
    
        ngx_uint_t status;  // 响应中的状态值,如200
        ngx_str_t status_line;  // 响应的状态行,如"HTTP/1.1 201 CREATED"
    
        // 以下成员设置后,ngx_http_header_filter_module过滤模块可以把它们加到待发送的网络包中
        ngx_table_elt_t *server;
        ngx_table_elt_t *date;
        ngx_table_elt_t *content_length;
        ngx_table_elt_t *content_encoding;
        ngx_table_elt_t *location;
        ngx_table_elt_t *refresh;
        ngx_table_elt_t *last_modified;
        ngx_table_elt_t *content_range;
        ngx_table_elt_t *accept_ranges;
        ngx_table_elt_t *www_authenticate;
        ngx_table_elt_t *expires;
        ngx_table_elt_t *etag;
    
        ngx_str_t *override_charset;
    
        // ngx_http_set_content_type()函数可根据URI中的文件扩展名并对应着mine.type来设置Content-Type
        size_t content_type_len;
        ngx_str_t content_type;
        ngx_str_t charset;
        u_char *content_type_lowcase;
        ngx_uint_t content_type_hash;
    
        ngx_array_t cache_control;
    
        off_t content_length_n;  // 设置该成员后,不需要再到content_length中设置响应长度
        off_t content_offset;
        time_t date_time;
        time_t last_modified_time;
    } ngx_http_headers_out_t;

      3)ngx_http_request_t(ngx_http_request.h):包含请求的所有信息(方法、URI、协议版本号和头部等)。

    typedef struct ngx_http_request_s ngx_http_request_t;
    struct ngx_http_request_s {
        // ...
        ngx_pool_t *pool;  // 指向该请求的内存池管理对象
        ngx_buf_t *header_in;  // 指向nginx收到的未经解析的HTTP头部(就是接收HTTP头部的缓冲区)
        ngx_http_headers_in_t headers_in;  // 存储已经解析过的HTTP(请求)头部
        ngx_http_headers_out_t headers_out;  // 存储响应中的HTTP头部
        // ...
        ngx_uint_t method;  // 如NGX_HTTP_GET、NGX_HTTP_HEAD
        ngx_uint_t http_version;
    
        ngx_str_t request_line;
        ngx_str_t uri;
        ngx_str_t args;  // 用户请求中的URL参数
        ngx_str_t exten;  // 用户请求的文件扩展名
        ngx_str_t unparsed_uri;  // 未进行URL解码的原始请求,如"/a%20b"
    
        ngx_str_t method_name;  // 用户请求中的方法名字符串
        ngx_str_t http_protocol;
        // ...
        u_char *uri_start;
        u_char *uri_end;  // 指向URI结束后的下一个地址
        u_char *uri_ext;
        u_char *args_start;
        u_char *request_start;  // nginx对内存的控制相当严格。为了避免不必要的内存开销,许多需要用到的成员都不是重新分配内存后存储的,
                                // 而是直接指向用户请求中的相应地址,如method_name.data和request_start这两个指针实际上指向的都是同一个地址
        u_char *request_end;
        u_char *method_end;  // 结合request_start与method_end(指向方法名的最后一个字符)可取得方法名
        u_char *schema_start;
        u_char *schema_end;
        // ...
    };

      4)ngx_http_module_t(ngx_http_config.h)

    typedef struct {
        ngx_int_t (*preconfiguration)(ngx_conf_t *cf);  // 解析配置文件前调用
        ngx_int_t (*postconfiguration)(ngx_conf_t *cf);  // 完成配置文件的解析后调用
    
        /* 当需要创建数据结构用于存储main级别(直属于http{}块的配置项)的全局配置项时,可以借助该回调函数 */
        void *(*create_main_conf)(ngx_conf_t *cf);
        char *(*init_main_conf)(ngx_conf_t *cf, void *conf);  // 常用于初始化main级别配置项
    
        /* 当需要创建数据结构用于存储srv级别(直属于虚拟主机server{}块)的配置项时,可以借助该回调函数 */
        void *(*create_srv_conf)(ngx_conf_t *cf);
        char *(*merge_srv_conf)(ngx_conf_t *cf, void *prev, void *conf);  // 主要用于合并main级别和srv级别下的同名配置项
    
        /* 当需要创建数据结构用于存储loc级别(直属于location{}块)的配置项时,可以借助该回调函数 */
        void *(*create_loc_conf)(ngx_conf_t *cf);
    /* 主要用于合并srv级别和loc级别下的同名配置项(合并方式可自定义,也可使用nginx预设的合并宏,如ngx_conf_merge_str_value)。参数:
    cf:提供一些基本数据结构(如内存池、日志);prev:指向解析父配置块时生成的结构体;conf:指向保存子配置块的结构体 */
    char *(*merge_loc_conf)(ngx_conf_t *cf, void *prev, void *conf); } ngx_http_module_t;

      5)ngx_http_conf_ctx_t(ngx_http_config.h)

    /* 当nginx检测到http{}时,HTTP配置模型就启动了,这时会首先建立1个ngx_http_conf_ctx_t结构
    HTTP框架会为所有的HTTP模块建立3个数组,分别存放所有HTTP模块的create_main_conf()、create_srv_conf()和create_loc_conf()返回的指针
    main_conf、srv_conf和loc_conf分别指向这3个数组
    */ typedef struct { void **main_conf; void **srv_conf; void **loc_conf; } ngx_http_conf_ctx_t;

      参考资料:

      《深入理解Nginx:模块开发与架构解析》

    不断学习中。。。

  • 相关阅读:
    layui的table使用,二
    将字符串中的以某个字符间隔放到数组中
    oracle中的 函数应用
    spring 的3种常用的注入方式
    写一个方法,输入两个正整数,输出在两个正整数范围内即被3整除,又被7整除的正整数
    Myeclipse 10.7配置egit及导入项目
    Plsqi安装
    web项目引入js包时,报syntax error on token
    java笔试面试题总结
    web.xml中的配置
  • 原文地址:https://www.cnblogs.com/hanerfan/p/6107660.html
Copyright © 2011-2022 走看看