nginx源码分析三----高级数据结构

    xiaoxiao2023-11-11  149

    一、 与框架相关

    ngx_cycle_t

    struct ngx_cycle_s { //保存存储所有模块的配置项的结构体指针 //之所以是4级指针,是因为conf_ctx首先是一个数组 //然后存储的元素是指针,该指针又指向另外一个指针数组 void ****conf_ctx; //内存池 ngx_pool_t *pool; /* 在还没有执行ngx_init_cycle之前(即没有解析配置项) * 若此时需要输出日志,就暂时用log,它会直接将信息输出到屏幕 * 当解析了配置项之后,会根据nginx.conf配置文件中的配置构建出要求的日志文件并将log重新赋值 */ ngx_log_t *log; ngx_log_t new_log; /* files保存所有ngx_connection_t的指针组成的数组 */ ngx_connection_t **files; /* 可用的连接池 */ ngx_connection_t *free_connections; /* 空闲连接的个数 */ ngx_uint_t free_connection_n; /* 双向链表, 存储的元素类型是ngx_connection_t, 代表可重复使用的连接队列 */ ngx_queue_t reusable_connections_queue; /* 动态数组, 存储类型为ngx_listening_t成员, 存储着监听的端口等信息 ngx_array_t listening; /* 动态数组, 保存nginx所有需要操作的目录, 如果系统中不存在这个目录, 则需要创建 * 若创建不成功, nginx启动会失败(比如没有权限什么的,所以master进程最好属于root) */ ngx_array_t pathes; /* 单链表, 存储类型为ngx_open_file_t结构体 * 它表示nginx已经打开的所有文件 * 由感兴趣的模块向其中添加文件路径名 * 然后在ngx_init_cycle函数中打开 */ ngx_list_t open_files; /* 单链表, 存储类型为ngx_shm_zone_t结构体 * 每个元素表示一块共享内存 */ ngx_list_t shared_memory; /* 所有连接对象的总数 */ ngx_uint_t connection_n; /* files数组里元素的总数 ngx_uint_t files_n; /* 指向所有连接对象 */ ngx_connection_t *connections; /* 指向所有读事件 */ ngx_event_t *read_events; /* 指向所有写事件 */ ngx_event_t *write_events; /* 在调用ngx_init_cycle之前,需要一个ngx_cycle_t临时变量来存储一些变量 * 调用ngx_init_cycle会将该临时变量传入 * old_cycle就负责保存这个临时变量 ngx_cycle_t *old_cycle; //配置文件相对安装目录的相对路径名 ngx_str_t conf_file; //需要特殊处理的在命令行携带的参数 ngx_str_t conf_param; //配置文件所在目录的路径 ngx_str_t conf_prefix; //安装目录的路径 ngx_str_t prefix; //文件锁名称 ngx_str_t lock_file; //主机名(通过gethostname系统调用获取) ngx_str_t hostname; };

    二、与配置相关

    ngx_conf_t

    描述: 该结构体用于Nginx在解析配置文件时描述每个指令的属性,也是Nginx程序中非常重要的一个数据结构 位置:ngx_conf_file.h

    char *name; //指令名 ngx_array_t *args; //指令的参数 ngx_cycle_t *cycle; ngx_pool_t *pool; ngx_pool_t *temp_pool; ngx_conf_file_t *conf_file; //存放nginx配置文件的相关信息 ngx_log_t *log; void *ctx; //描述指令的上下文 ngx_uint_t module_type; // 支持该指令的模块的类型,core、http、event和mail中的一种。 ngx_uint_t cmd_type; //指令的类型 ngx_conf_handler_pt handler; //指令对应的处理函数 void *handler_conf; };

    说明: 在解析配置文件时,每解析一个指令,都会生成一个ngx_conf_t结构体,并保存该指令对应的参数,上下文信息,以及对应的handler处理函数。

    ngx_http_conf_ctx_t

    描述 : nginx启动时解析配置文件nginx.conf,当发现http块时,会依次调用所有http模块的create_main_conf,create_srv_conf,create_loc_conf方法,这些方法都是用来创建各个模块存储自身配置项的结构体。 nginx会将这些结构体的地址指针存放在main_conf,srv_conf,loc_conf的成员里。 位置:ngx_http.c

    struct ngx_http_conf_ctx_t { void **main_conf; void **srv_conf; void **loc_conf; }

    ngx_http_upstream_main_conf_t

    作用:存储main段upstream的相关配置 位置:ngx_http_upstream_t

    typedef struct { ngx_hash_t headers_in_hash; //其他模块配置的hash头部信息 ngx_array_t upstreams; //每一个upstream都存储upstreams数组里。每个upstream都对应一个ngx_http_upstream_srv_conf_t 结构体。 /* ngx_http_upstream_srv_conf_t */ } ngx_http_upstream_main_conf_t;

    ngx_http_upstream_srv_conf_t

    作用 : 存储单个upstream的配置 位置:ngx_http_upstream_t

    struct ngx_http_upstream_srv_conf_s { ngx_http_upstream_peer_t peer; void **srv_conf; ngx_array_t *servers; /* ngx_http_upstream_server_t */ ngx_uint_t flags; ngx_str_t host; u_char *file_name; ngx_uint_t line; in_port_t port; ngx_uint_t no_port; /* unsigned no_port:1 */ #if (NGX_HTTP_UPSTREAM_ZONE) ngx_shm_zone_t *shm_zone; #endif };

    三 、与模块相关

    ngx_module_t

    struct ngx_module_t { /* 当前模块在这一类模块中的位置 */ ngx_uint_t ctx_index /* 当前模块在所有模块中的位置 */ ngx_uint_t index /* 模块的上下文结构体,如果是HTTP模块,这ctx指向ngx_http_module_t结构体*/ void *ctx /* 模块支持的配置指令 */ ngx_command_t *commands }

    ngx_http_module_t

    struct ngx_http_module_t { preconfiguration postconfiguration create_main_conf init_main_conf create_srv_conf create_loc_conf merge_srv_conf merge_loc_conf }

    ngx_command_t

    struct ngx_command_s { ngx_str_t name; //指令名称 ngx_uint_t type; // 指令能出现的位置 char *(*set)(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); //调用set方法处理配置项的参数 ngx_uint_t conf; ngx_uint_t offset; void *post; };

    ngx_core_conf_t : core模块存储配置项的结构体

    ngx_process_t:用来记录每个worker子进程的基本信息,Nginx使用一个全局数组保存所有产生的子进程,这就是近程池ngx_processes,这个数组是静态分配的,不能动态增长,Nginx只支持1024个子进程(也就是worker进程),这远大于目前主流计算机CPU核心数量,足够用了。

    typedef struct { //进程的id号 ngx_pid_t pid; //通过waitpid系统调用获取到的进程状态 int status; //通过socketpair系统调用产生的用于进程间通信的一对socket,用于相互通信。 ngx_socket_t channel[2]; //子进程的工作循环 ngx_spawn_proc_pt proc; //proc的第二个参数,可能需要传入一些数据 void *data; //进程名称 char *name; //一些标识位 //为1时代表需要重新生成子进程 unsigned respawn : 1; //为1代表需要生成子进程 unsigned just_spawn : 1; //为1代表需要进行父、子进程分离 unsigned detached : 1; //为1代表进程正在退出 unsigned exiting : 1; //为1代表进程已经退出了 unsigned exited : 1; } ngx_process_t;

    ngx_connection_t:nginx的连接池

    四 与请求相关

    ngx_http_request_t

    描述::nginx的每个http请求都对应这个这样一个结构体 位置: ngx_http_request.h

    struct ngx_http_request_s { uint32_t signature; /* "HTTP" */ ngx_connection_t *connection; void **ctx; //保存所有http模块上下文结构体的指针 void **main_conf; void **srv_conf; void **loc_conf; ngx_http_event_handler_pt read_event_handler; ngx_http_event_handler_pt write_event_handler; #if (NGX_HTTP_CACHE) ngx_http_cache_t *cache; #endif ngx_http_upstream_t *upstream; ngx_array_t *upstream_states; /* of ngx_http_upstream_state_t */ ngx_pool_t *pool; //请求内存池 ngx_buf_t *header_in; // 未被nginx解析的头部,主要是那些非RFC2616标准的头部,实际上,header_in就是接受http头部的缓冲区。 ngx_http_headers_in_t headers_in; // 存储解析过的http头部信息 ngx_http_headers_out_t headers_out; ngx_http_request_body_t *request_body; time_t lingering_time; time_t start_sec; ngx_msec_t start_msec; ngx_uint_t method; ngx_uint_t http_version; ngx_str_t request_line; ngx_str_t uri; ngx_str_t args; ngx_str_t exten; ngx_str_t unparsed_uri; ngx_str_t method_name; ngx_str_t http_protocol; ngx_chain_t *out; ngx_http_request_t *main; ngx_http_request_t *parent; ngx_http_postponed_request_t *postponed; ngx_http_post_subrequest_t *post_subrequest; ngx_http_posted_request_t *posted_requests; ngx_int_t phase_handler; ngx_http_handler_pt content_handler; ngx_uint_t access_code; ngx_http_variable_value_t *variables; #if (NGX_PCRE) ngx_uint_t ncaptures; int *captures; u_char *captures_data; #endif size_t limit_rate; size_t limit_rate_after; /* used to learn the Apache compatible response length without a header */ size_t header_size; off_t request_length; ngx_uint_t err_status; ngx_http_connection_t *http_connection; ngx_http_v2_stream_t *stream; ngx_http_log_handler_pt log_handler; ngx_http_cleanup_t *cleanup; unsigned count:16; unsigned subrequests:8; unsigned blocked:8; unsigned aio:1; unsigned http_state:4; /* URI with "/." and on Win32 with "//" */ unsigned complex_uri:1; /* URI with "%" */ unsigned quoted_uri:1; /* URI with "+" */ unsigned plus_in_uri:1; /* URI with " " */ unsigned space_in_uri:1; unsigned invalid_header:1; unsigned add_uri_to_alias:1; unsigned valid_location:1; unsigned valid_unparsed_uri:1; unsigned uri_changed:1; unsigned uri_changes:4; unsigned request_body_in_single_buf:1; unsigned request_body_in_file_only:1; unsigned request_body_in_persistent_file:1; unsigned request_body_in_clean_file:1; unsigned request_body_file_group_access:1; unsigned request_body_file_log_level:3; unsigned request_body_no_buffering:1; unsigned subrequest_in_memory:1; unsigned waited:1; #if (NGX_HTTP_CACHE) unsigned cached:1; #endif #if (NGX_HTTP_GZIP) unsigned gzip_tested:1; unsigned gzip_ok:1; unsigned gzip_vary:1; #endif unsigned proxy:1; unsigned bypass_cache:1; unsigned no_cache:1; /* * instead of using the request context data in * ngx_http_limit_conn_module and ngx_http_limit_req_module * we use the single bits in the request structure */ unsigned limit_conn_set:1; unsigned limit_req_set:1; #if 0 unsigned cacheable:1; #endif unsigned pipeline:1; unsigned chunked:1; unsigned header_only:1; unsigned expect_trailers:1; unsigned keepalive:1; unsigned lingering_close:1; unsigned discard_body:1; unsigned reading_body:1; unsigned internal:1; unsigned error_page:1; unsigned filter_finalize:1; unsigned post_action:1; unsigned request_complete:1; unsigned request_output:1; unsigned header_sent:1; unsigned expect_tested:1; unsigned root_tested:1; unsigned done:1; unsigned logged:1; unsigned buffered:4; unsigned main_filter_need_in_memory:1; unsigned filter_need_in_memory:1; unsigned filter_need_temporary:1; unsigned preserve_body:1; unsigned allow_ranges:1; unsigned subrequest_ranges:1; unsigned single_range:1; unsigned disable_not_modified:1; unsigned stat_reading:1; unsigned stat_writing:1; unsigned stat_processing:1; unsigned background:1; unsigned health_check:1; /* used to parse HTTP headers */ ngx_uint_t state; ngx_uint_t header_hash; ngx_uint_t lowcase_index; u_char lowcase_header[NGX_HTTP_LC_HEADER_LEN]; u_char *header_name_start; u_char *header_name_end; u_char *header_start; u_char *header_end; /* * a memory that can be reused after parsing a request line * via ngx_http_ephemeral_t */ u_char *uri_start; u_char *uri_end; u_char *uri_ext; u_char *args_start; u_char *request_start; u_char *request_end; u_char *method_end; u_char *schema_start; u_char *schema_end; u_char *host_start; u_char *host_end; u_char *port_start; u_char *port_end; unsigned http_minor:16; unsigned http_major:16; };

    说明: 1 ctx成员保存着每一个http模块上下文结构体的指针,http框架并不关心请求的上下文信息, 每个请求自己维护自己的ctx成员。

    ngx_http_header_in_t

    描述: ngx_http_request_t的一个成员,用于存储当前请求被解析过的请求头

    typedef struct { ngx_list_t headers; // 非标准的HTTP头都存放在headers的链表里,如果要获取,则必须遍历该链表 // 以下的都是标准的http头部,直接访问成员变量就行,如果没有解析到该头部,这对应的ngx_table_elt_t指针为NULL ngx_table_elt_t *host; ngx_table_elt_t *connection; ngx_table_elt_t *if_modified_since; ngx_table_elt_t *if_unmodified_since; ngx_table_elt_t *if_match; ngx_table_elt_t *if_none_match; ngx_table_elt_t *user_agent; ngx_table_elt_t *referer; ngx_table_elt_t *content_length; ngx_table_elt_t *content_range; ngx_table_elt_t *content_type; ngx_table_elt_t *range; ngx_table_elt_t *if_range; ngx_table_elt_t *transfer_encoding; ngx_table_elt_t *expect; ngx_table_elt_t *upgrade; #if (NGX_HTTP_GZIP) ngx_table_elt_t *accept_encoding; ngx_table_elt_t *via; #endif ngx_table_elt_t *authorization; ngx_table_elt_t *keep_alive; #if (NGX_HTTP_X_FORWARDED_FOR) ngx_array_t x_forwarded_for; #endif #if (NGX_HTTP_REALIP) ngx_table_elt_t *x_real_ip; #endif #if (NGX_HTTP_HEADERS) ngx_table_elt_t *accept; ngx_table_elt_t *accept_language; #endif #if (NGX_HTTP_DAV) ngx_table_elt_t *depth; ngx_table_elt_t *destination; ngx_table_elt_t *overwrite; ngx_table_elt_t *date; #endif ngx_str_t user; ngx_str_t passwd; ngx_array_t cookies; ngx_str_t server; off_t content_length_n; time_t keep_alive_n; unsigned connection_type:2; 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;

    ngx_http_headers_out_t

    typedef struct { // 待发送的HTTP的头部链表,与ngx_http_request_t中headers_in中的headers成员类似。 ngx_list_t headers; ngx_list_t trailers; ngx_uint_t status; ngx_str_t status_line; // 一下成员(包括ngx_table_elt_t)都是RFC1616定义的标准的http头部,设置之后通过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; 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; off_t content_offset; time_t date_time; time_t last_modified_time; } ngx_http_headers_out_t;

    重要的底层函数:

    ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module); ngx_http_discard_request_body®; 丢弃请求中的包体

    字符串相关

    1 字符串比较:ngx_strcmp()与ngx_strcasecmp() 后者不区分大小写 2 比较字符串前n个字符: ngx_strncmp()与ngx_strncasecmp() 示例见<深入理解nginx> P97

    输入输出相关:

    1 日志 2 标准输出

    (三) nginx处理http request的流程

    三个重要的handler函数: 行handler: ngx_http_process_request_line ngx_http_read_request_header: 读取行 ngx_http_parse_request_line: 解析行 头handler:ngx_http_process_request_headers ngx_http_read_request_header: 读取头 ngx_http_parse_header_line:解析头 先不读body,读取到两个换行符时,开始处理请求: 处理请求handler: ngx_http_process_request ngx_http_handler 读事件:read_event_handler 写事件:write_event_handler = ngx_http_core_run_phases
    最新回复(0)