重要的结构体
1. nginx_cycle_t
struct ngx_cycle_s { void ****conf_ctx; //配置上下文数组(含所有模块) ngx_pool_t *pool; //内存池 ngx_log_t *log; //日志 ngx_log_t new_log; ngx_connection_t **files; //连接文件 ngx_connection_t *free_connections; //空闲连接 ngx_uint_t free_connection_n; //空闲连接个数 ngx_queue_t reusable_connections_queue; //再利用连接队列 ngx_array_t listening; //监听数组 ngx_array_t pathes; //路径数组 ngx_list_t open_files; //打开文件链表 ngx_list_t shared_memory; //共享内存链表 ngx_uint_t connection_n; //连接个数 ngx_uint_t files_n; //打开文件个数 ngx_connection_t *connections; //连接 ngx_event_t *read_events; //读事件 ngx_event_t *write_events; //写事件 ngx_cycle_t *old_cycle; //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; //锁文件 ngx_str_t hostname; //主机名 };2. nginx_conf_t
struct ngx_conf_s { char *name; ngx_array_t *args;//每解析一行,从配置文件中解析出的配置项全部在这里面 //最终指向的是一个全局类型的ngx_cycle_s,即ngx_cycle,见ngx_init_cycle ngx_cycle_t *cycle; //指向对应的cycle,见ngx_init_cycle中的两行conf.ctx = cycle->conf_ctx; conf.cycle = cycle; ngx_pool_t *pool; ngx_pool_t *temp_pool; //用该poll的空间都是临时空间,最终在ngx_init_cycle->ngx_destroy_pool(conf.temp_pool);中释放 ngx_conf_file_t *conf_file; //nginx.conf ngx_log_t *log; //cycle->conf_ctx = ngx_pcalloc(pool, ngx_max_module * sizeof(void *)); //指向ngx_cycle_t->conf_ctx 有多少个模块,就有多少个ctx指针数组成员 conf.ctx = cycle->conf_ctx;见ngx_init_cycle //这个ctx每次在在进入对应的server{} location{}前都会指向零时保存父级的ctx,该{}解析完后在恢复到父的ctx。可以参考ngx_http_core_server,ngx_http_core_location void *ctx;//指向结构ngx_http_conf_ctx_t ngx_core_module_t ngx_event_module_t ngx_stream_conf_ctx_t等 ngx_uint_t module_type; //表示当前配置项是属于那个大类模块 取值有如下5种:NGX_HTTP_MODULE、NGX_CORE_MODULE、NGX_CONF_MODULE、NGX_EVENT_MODULE、NGX_MAIL_MODULE ngx_uint_t cmd_type; //大类里面的那个子类模块,如NGX_HTTP_SRV_CONF NGX_HTTP_LOC_CONF等 ngx_conf_handler_pt handler; char *handler_conf; };3. nginx_connection_t : 每个连接都对应这样一个结构体
4. nginx_buf_t
struct ngx_buf_s { //可以参考ngx_create_temp_buf 函数空间在ngx_create_temp_buf创建,让指针指向这些空间 /*pos通常是用来告诉使用者本次应该从pos这个位置开始处理内存中的数据,这样设置是因为同一个ngx_buf_t可能被多次反复处理。 当然,pos的含义是由使用它的模块定义的*/ //它的pos成员和last成员指向的地址之间的内存就是接收到的还未解析的字符流 u_char *pos; //pos指针指向从内存池里分配的内存。 pos为已扫描的内存端中,还未解析的内存的尾部, u_char *last;/*last通常表示有效的内容到此为止,注意,pos与last之间的内存是希望nginx处理的内容*/ /* 处理文件时,file_pos与file_last的含义与处理内存时的pos与last相同,file_pos表示将要处理的文件位置,file_last表示截止的文件位置 */ off_t file_pos; //可以结合ngx_output_chain_copy_buf阅读更好理解 输出数据的打印可以在ngx_http_write_filter中查看调试信息 //也就是实际存到临时文件中的字节数,见ngx_event_pipe_write_chain_to_temp_file off_t file_last; //写入文件内容的最尾处的长度赋值见ngx_http_read_client_request_body 输出数据的打印可以在ngx_http_write_filter中查看调试信息 //如果ngx_buf_t缓冲区用于内存,那么start指向这段内存的起始地址 u_char *start; /* start of buffer */ //创建空间见ngx_http_upstream_process_header u_char *end; /* end of buffer */ //与start成员对应,指向缓冲区内存的末尾 //ngx_http_request_body_length_filter中赋值为ngx_http_read_client_request_body //实际上是一个void*类型的指针,使用者可以关联任意的对象上去,只要对使用者有意义。 ngx_buf_tag_t tag;/*表示当前缓冲区的类型,例如由哪个模块使用就指向这个模块ngx_module_t变量的地址*/ ngx_file_t *file;//引用的文件 用于存储接收到所有包体后,把包体内容写入到file文件中,赋值见ngx_http_read_client_request_body /*当前缓冲区的影子缓冲区,该成员很少用到,仅仅在使用缓冲区转发上游服务器的响应时才使用了shadow成员,这是因为Nginx太节 约内存了,分配一块内存并使用ngx_buf_t表示接收到的上游服务器响应后,在向下游客户端转发时可能会把这块内存存储到文件中,也 可能直接向下游发送,此时Nginx绝不会重新复制一份内存用于新的目的,而是再次建立一个ngx_buf_t结构体指向原内存,这样多个 ngx_buf_t结构体指向了同一块内存,它们之间的关系就通过shadow成员来引用。这种设计过于复杂,通常不建议使用 当这个buf完整copy了另外一个buf的所有字段的时候,那么这两个buf指向的实际上是同一块内存,或者是同一个文件的同一部分,此 时这两个buf的shadow字段都是指向对方的。那么对于这样的两个buf,在释放的时候,就需要使用者特别小心,具体是由哪里释放,要 提前考虑好,如果造成资源的多次释放,可能会造成程序崩溃! */ ngx_buf_t *shadow; //参考ngx_http_fastcgi_input_filter /* the buf's content could be changed */ //为1时表示该buf所包含的内容是在一个用户创建的内存块中,并且可以被在filter处理的过程中进行变更,而不会造成问题 unsigned temporary:1; //临时内存标志位,为1时表示数据在内存中且这段内存可以修改 /* * the buf's content is in a memory cache or in a read only memory * and must not be changed */ //为1时表示该buf所包含的内容是在内存中,但是这些内容确不能被进行处理的filter进行变更。 unsigned memory:1;//标志位,为1时表示数据在内存中且这段内存不可以被修改 /* the buf's content is mmap()ed and must not be changed */ //为1时表示该buf所包含的内容是在内存中, 是通过mmap使用内存映射从文件中映射到内存中的,这些内容确不能被进行处理的filter进行变更。 unsigned mmap:1;//标志位,为1时表示这段内存是用mmap系统调用映射过来的,不可以被修改 //可以回收的。也就是这个buf是可以被释放的。这个字段通常是配合shadow字段一起使用的,对于使用ngx_create_temp_buf 函数创建的buf, //并且是另外一个buf的shadow,那么可以使用这个字段来标示这个buf是可以被释放的。 //置1了表示该buf需要马上发送出去,参考ngx_http_write_filter -> if (!last && !flush && in && size < (off_t) clcf->postpone_output) { unsigned recycled:1; //标志位,为1时表示可回收利用,当该buf被新的buf指针指向的时候,就置1,见ngx_http_upstream_send_response /* ngx_buf_t有一个标志位in_file,将in_file置为1就表示这次ngx_buf_t缓冲区发送的是文件而不是内存。 调用ngx_http_output_filter后,若Nginx检测到in_file为1,将会从ngx_buf_t缓冲区中的file成员处获取实际的文件。file的类型是ngx_file_t */ //为1时表示该buf所包含的内容是在文件中。 输出数据的打印可以在ngx_http_write_filter中查看调试信息 unsigned in_file:1;//标志位,为1时表示这段缓冲区处理的是文件而不是内存,说明包体全部存入文件中,需要配置"client_body_in_file_only" on | clean //遇到有flush字段被设置为1的的buf的chain,则该chain的数据即便不是最后结束的数据(last_buf被设置,标志所有要输出的内容都完了), //也会进行输出,不会受postpone_output配置的限制,但是会受到发送速率等其他条件的限制。 置1了表示该buf需要马上发送出去,参考ngx_http_write_filter -> if (!last && !flush && in && size < (off_t) clcf->postpone_output) { unsigned flush:1;//标志位,为1时表示需要执行flush操作 标示需要立即发送缓冲的所有数据; /*标志位,对于操作这块缓冲区时是否使用同步方式,需谨慎考虑,这可能会阻塞Nginx进程,Nginx中所有操作几乎都是异步的,这是 它支持高并发的关键。有些框架代码在sync为1时可能会有阻塞的方式进行I/O操作,它的意义视使用它的Nginx模块而定*/ unsigned sync:1; /*标志位,表示是否是最后一块缓冲区,因为ngx_buf_t可以由ngx_chain_t链表串联起来,因此,当last_buf为1时,表示当前是最后一块待处理的缓冲区*/ /* 如果接受包体接收完成,则存储最后一个包体内容的buf的last_buf置1,见ngx_http_request_body_length_filter 如果发送包体的时候只有头部,这里会置1,见ngx_http_header_filter 如果各个模块在发送包体内容的时候,如果送入ngx_http_write_filter函数的in参数chain表中的某个buf为该包体的最后一段内容,则该buf中的last_buf会置1 */ // ngx_http_send_special中会置1 见ngx_http_write_filter -> if (!last && !flush && in && size < (off_t) clcf->postpone_output) { //置1了表示该buf需要马上发送出去,参考ngx_http_write_filter -> if (!last && !flush && in && size < (off_t) clcf->postpone_output) { unsigned last_buf:1; //数据被以多个chain传递给了过滤器,此字段为1表明这是最后一个chain。 //在当前的chain里面,此buf是最后一个。特别要注意的是last_in_chain的buf不一定是last_buf,但是last_buf的buf一定是last_in_chain的。这是因为数据会被以多个chain传递给某个filter模块。 unsigned last_in_chain:1;//标志位,表示是否是ngx_chain_t中的最后一块缓冲区 //在创建一个buf的shadow的时候,通常将新创建的一个buf的last_shadow置为1。 //参考ngx_http_fastcgi_input_filter //当数据被发送出去后,该标志位1的ngx_buf_t最终会添加到free_raw_bufs中 //该值一般都为1, unsigned last_shadow:1; /*标志位,表示是否是最后一个影子缓冲区,与shadow域配合使用。通常不建议使用它*/ unsigned temp_file:1;//标志位,表示当前缓冲区是否属于临时文件 /* STUB */ int num; //是为读取后端服务器包体分配的第几个buf ,见ngx_event_pipe_read_upstream 表示属于链表chain中的第几个buf };5. nginx_request_t : 一个请求对应一个 nginx_request_t 结构体
6. ngx_pool_t : 内存池
typedef struct { u_char *last; //当前内存池分配到此处,即下一次分配从此处开始 u_char *end; //内存池结束位置 ngx_pool_t *next; //内存池里面有很多块内存,这些内存块就是通过该指针连成链表的 ngx_uint_t failed; //内存池分配失败次数 } ngx_pool_data_t; //内存池的数据块位置信息 struct ngx_pool_s{ //内存池头部结构 ngx_pool_data_t d; //内存池的数据块 size_t max; //内存池数据块的最大值 ngx_pool_t *current; //指向当前内存池 ngx_chain_t *chain; //该指针挂接一个ngx_chain_t结构 ngx_pool_large_t *large; //大块内存链表,即分配空间超过max的内存 ngx_pool_cleanup_t *cleanup; //释放内存池的callback ngx_log_t *log; //日志信息 };7. ngx_event_t : 每个事件都对应这样一个结构体
8. ngx_array_t :动态数组 (操作数组的几个API)
struct ngx_array_s { void *elts; //数组数据区起始位置 ngx_uint_t nelts; //实际存放的元素个数 size_t size; //每个元素大小 ngx_uint_t nalloc; //数组所含空间个数,即实际分配的小空间的个数 ngx_pool_t *pool; //该数组在此内存池中分配 }; typedef struct ngx_array_s ngx_array_t;9. ngx_listending_t
struct ngx_listening_s { ngx_socket_t fd;//套接字句柄 struct sockaddr *sockaddr;//监听sockaddr地址 socklen_t socklen; /*sockaddr地址长度 size of sockaddr */ size_t addr_text_max_len;//存储ip地址的字符串addr_text最大长度 ngx_str_t addr_text;//以字符串形式存储ip地址 //套接字类型。types是SOCK_STREAM时,表示是tcp int type; //TCP实现监听时的backlog队列,它表示允许正在通过三次握手建立tcp连接但还没有任何进程开始处理的连接最大个数 int backlog; int rcvbuf;//套接字接收缓冲区大小 int sndbuf;//套接字发送缓冲区大小 /* handler of accepted connection */ ngx_connection_handler_pt handler;//当新的tcp连接成功建立后的处理方法 //目前主要用于HTTP或者mail等模块,用于保存当前监听端口对应着的所有主机名 void *servers; /* array of ngx_http_in_addr_t, for example */ ngx_log_t log;//日志 ngx_log_t *logp;//日志指针 size_t pool_size;//如果为新的tcp连接创建内存池,则内存池的初始大小应该是pool_size。 /* should be here because of the AcceptEx() preread */ size_t post_accept_buffer_size; /* should be here because of the deferred accept */ ngx_msec_t post_accept_timeout;//~秒后仍然没有收到用户的数据,就丢弃该连接 //前一个ngx_listening_t结构,用于组成单链表 ngx_listening_t *previous; ngx_connection_t *connection;//当前监听句柄对应的ngx_connection_t结构体 unsigned open:1;//为1表示监听句柄有效,为0表示正常关闭 unsigned remain:1;//为1表示不关闭原先打开的监听端口,为0表示关闭曾经打开的监听端口 unsigned ignore:1;//为1表示跳过设置当前ngx_listening_t结构体中的套接字,为0时正常初始化套接字 unsigned bound:1; /* already bound */ unsigned inherited:1; /* inherited from previous process */ unsigned nonblocking_accept:1; unsigned listen:1;//为1表示当前结构体对应的套接字已经监听 unsigned nonblocking:1; unsigned shared:1; /* shared between threads or processes */ unsigned addr_ntop:1;//为1表示将网络地址转变为字符串形式的地址 #if (NGX_HAVE_INET6 && defined IPV6_V6ONLY) unsigned ipv6only:2; #endif #if (NGX_HAVE_DEFERRED_ACCEPT) unsigned deferred_accept:1; unsigned delete_deferred:1; unsigned add_deferred:1; #ifdef SO_ACCEPTFILTER char *accept_filter; #endif #endif #if (NGX_HAVE_SETFIB) int setfib; #endif };10 ngx_socket_t : int
11. ngx_list_t : 链表
12. ngx_queue_t : 队列
13. ngx_path_t:
typedef struct { //fastcgi_cache_path /tmp/nginx/fcgi/cache levels=1:2 keys_zone=fcgi:10m inactive=30m max_size=128m;中的levels=1:2中的1:2中的/tmp/nginx/fcgi/cache ngx_str_t name; //路径名 //可以参考下ngx_create_hashed_filename size_t len; //levels=x:y最终的结果是path->len = (x+1) + (y+1) 参考ngx_http_file_cache_set_slot /* levels=1:2,意思是说使用两级目录,第一级目录名是一个字符,第二级用两个字符。但是nginx最大支持3级目录,即levels=xxx:xxx:xxx。 那么构成目录名字的字符哪来的呢?假设我们的存储目录为/cache,levels=1:2,那么对于上面的文件 就是这样存储的: /cache/0/8d/8ef9229f02c5672c747dc7a324d658d0 注意后面的8d0和cache后面的/0/8d一致 参考ngx_create_hashed_filename */ //fastcgi_cache_path /tmp/nginx/fcgi/cache levels=1:2 keys_zone=fcgi:10m inactive=30m max_size=128m;中的levels=1:2中的1:2 //目录创建见ngx_create_path //一个对应的缓存文件的目录f/27/46492fbf0d9d35d3753c66851e81627f中的46492fbf0d9d35d3753c66851e81627f,注意f/27就是最尾部的字节,这个由levle=1:2,就是最后面的1个字节+2个字节 size_t level[3]; //把levels=x:y;中的x和y分别存储在level[0]和level[1] level[3]始终为0 //ngx_http_file_cache_set_slot中设置为ngx_http_file_cache_manager //一般只有涉及到共享内存分配管理的才有该pt,例如fastcgi_cache_path xxx keys_zone=fcgi:10m xxx 只要有这些配置则会启用cache进程,见ngx_start_cache_manager_processes ngx_path_manager_pt manager; //ngx_cache_manager_process_handler中执行 //manger和loader。是cache管理回调函数 //ngx_http_file_cache_set_slot中设置为ngx_http_file_cache_loader ngx_cache_loader_process_handler中执行 ngx_path_loader_pt loader; //决定是否启用cache loader进程 参考ngx_start_cache_manager_processes void *data; //ngx_http_file_cache_set_slot中设置为ngx_http_file_cache_t u_char *conf_file; //所在的配置文件 见ngx_http_file_cache_set_slot ngx_uint_t line; //在配置文件中的行号,见ngx_http_file_cache_set_slot } ngx_path_t;14. ngx_module_t
struct ngx_module_s { ngx_uint_t ctx_index; // ctx index表明了模块在相同类型模块中的顺序 /*分类的模块计数器 nginx模块可以分为四种:core、event、http和mail 每个模块都会各自计数,ctx_index就是每个模块在其所属类组的计数*/ ngx_uint_t index; /*一个模块计数器,按照每个模块在ngx_modules[]数组中的声明顺序,从0开始依次给每个模块赋值*/ ngx_uint_t spare0; ngx_uint_t spare1; ngx_uint_t spare2; ngx_uint_t spare3; ngx_uint_t version; //nginx模块版本 void *ctx; /*模块的上下文,不同种类的模块有不同的上下文,因此实现了四种结构体*/ ngx_command_t *commands; /*命令定义地址 模块的指令集 每一个指令在源码中对应着一个ngx_command_t结构变量*/ ngx_uint_t type; //模块类型,用于区分core event http和mail ngx_int_t (*init_master)(ngx_log_t *log); //初始化master时执行 ngx_int_t (*init_module)(ngx_cycle_t *cycle); //初始化module时执行 ngx_int_t (*init_process)(ngx_cycle_t *cycle); //初始化process时执行 ngx_int_t (*init_thread)(ngx_cycle_t *cycle); //初始化thread时执行 void (*exit_thread)(ngx_cycle_t *cycle); //退出thread时执行 void (*exit_process)(ngx_cycle_t *cycle); //退出process时执行 void (*exit_master)(ngx_cycle_t *cycle); //退出master时执行 //以下功能不明 uintptr_t spare_hook0; uintptr_t spare_hook1; uintptr_t spare_hook2; uintptr_t spare_hook3; uintptr_t spare_hook4; uintptr_t spare_hook5; uintptr_t spare_hook6; uintptr_t spare_hook7; };15. ngx_core_conf_t
typedef struct { //从ngx_cycle_s->conf_ctx[ngx_core_module.index]指向这里 ngx_flag_t daemon; ngx_flag_t master; //在ngx_core_module_init_conf中初始化为1 通过参数"master_process"设置 ngx_msec_t timer_resolution; //从timer_resolution全局配置中解析到的参数,表示多少ms执行定时器中断,然后epoll_wail会返回跟新内存时间 ngx_int_t worker_processes; //创建的worker进程数,通过nginx配置,默认为1 "worker_processes"设置 ngx_int_t debug_points; //修改工作进程的打开文件数的最大值限制(RLIMIT_NOFILE),用于在不重启主进程的情况下增大该限制。 ngx_int_t rlimit_nofile; //修改工作进程的core文件尺寸的最大值限制(RLIMIT_CORE),用于在不重启主进程的情况下增大该限制。 off_t rlimit_core;//worker_rlimit_core 1024k; coredump文件大小 int priority; /* worker_processes 4; worker_cpu_affinity 0001 0010 0100 1000; 四个工作进程分别在四个指定的he上面运行 如果是5he可以这样配置 worker_cpu_affinity 00001 00010 00100 01000 10000; 其他多核类似 */ //参考ngx_set_cpu_affinity ngx_uint_t cpu_affinity_n; //worker_cpu_affinity参数个数 uint64_t *cpu_affinity;//worker_cpu_affinity 00001 00010 00100 01000 10000;转换的位图结果就是0X11111 char *username; ngx_uid_t user; ngx_gid_t group; ngx_str_t working_directory;//working_directory /var/yyz/corefile/; coredump存放路径 ngx_str_t lock_file; ngx_str_t pid; //默认NGX_PID_PATH,主进程名 ngx_str_t oldpid;//NGX_PID_PATH+NGX_OLDPID_EXT 热升级nginx进程的时候用 //数组第一个成员是TZ字符串 ngx_array_t env;//成员类型ngx_str_t,见ngx_core_module_create_conf char **environment; //直接指向env,见ngx_set_environment } ngx_core_conf_t;16. ngx_conf_file_t
typedef struct { //对应的是核心模块NGX_CORE_MODULE,在ngx_init_cycle中执行 ngx_str_t name; void *(*create_conf)(ngx_cycle_t *cycle); //它还提供了init_conf回调方法,用于在解析完配置文件后,使用解析出的配置项初始化核心模块功能。 char *(*init_conf)(ngx_cycle_t *cycle, void *conf); } ngx_core_module_t; typedef struct { ngx_file_t file; //配置文件名 ngx_buf_t *buffer; //文件内容在这里面存储 //当在解析从文件中读取到的4096字节内存时,如果最后面的内存不足以构成一个token, //则把这部分内存零时存起来,然后拷贝到下一个4096内存的头部参考ngx_conf_read_token ngx_buf_t *dump; ngx_uint_t line; //在配置文件中的行号 可以参考ngx_thread_pool_add } ngx_conf_file_t;二、 nginx中重要的数据结构
三、 nginx与php交互的过程: https://blog.csdn.net/misakaqunianxiatian/article/details/52651071
