nginx源码解析之常用数据结构

时间:2022-05-27 10:21:28

  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:模块开发与架构解析》

 

 

不断学习中。。。