前言
继续源码。。。
核心结构
Nginx核心的框架代码是一直在围绕 ngx_cycle_t这个核心结构体来控制进程运行的。
无论是master管理进程,worker工作进程还是cache manager(loader)进程,它们都毫无例外地拥有唯一的一个ngx_cycle_t结构体。
ngx_cycle_t结构体
首先,Nginx的可配置性完全依赖于nginx.conf配置文件,Nginx所有模块的可定制性、可伸缩性等诸多特性也依赖于nginx.conf配置文件,因此,配置文件路径需要保存在ngx_cycle_t中;有了配置文件后,Nginx框架就需要开始根据配置项加载所有模块。......。
下面,介绍下ngx_cycle_t的成员:
typedef struct ngx_cycle_s ngx_cycle_t;
struct ngx_cycle_s {
/*
* 保存所有模块存储配置项的结构体指针
* 为什么是四重指针?之前已有笔记,详见《笔记五》中的<设定配置项解析方式>
*/
void ****conf_ctx;
ngx_pool_t *pool; // 内存池
/*
* 在没有执行ngx_init_cycle方法之前,即没有解析配置项前,如果有信息输出到日志,
* 会暂时使用此成员,将log输出到屏幕。在使用ngx_init_cycle方法后,则会根据nginx.conf
* 配置文件中的配置项,构造出正确的日者文件,此时对log重新赋值
*/
ngx_log_t *log;
/*
* 由nginx.conf配置文件读取到日志文件路径后,开始初始化error_log日志文件,
* 此时,因为上面log成员还在用于输出日志到屏幕,则用此成员暂时替代log成员,
* 待初始化成功后,再用new_log成员的地址覆盖log指针
*/
ngx_log_t new_log;
ngx_uint_t log_use_stderr; /* unsigned log_use_stderr:1; */
/* 对于poll、rtsig事件模块,Nginx会以有效句柄数预先建立ngx_connection_t结构,
* 以加速事件收集、分发。这时,此成员保存所有ngx_connection_t指针组成的数组,
* 下面的file_n表示指针总数,文件句柄值用来访问files成员
*/
ngx_connection_t **files;
/* 可用连接池,与free_connection_n(可用连接池中连接数目)配合使用 */
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启动失败
*/
ngx_array_t paths;
/* 单向链表容器,元素类型为ngx_open_file_t结构
* 表示Nginx已经打开所有文件。Nginx框架会在ngx_init_cycle中打开这些文件
*/
ngx_list_t open_files;
/* 单向链表容器,元素类型为ngx_shm_zone_t结构,每个元素表示一块共享内存。之后在Nginx进程间通信章节再学习 */
ngx_list_t shared_memory;
/* 当前进程中所有连接对象的数目,与下面connections成员配合使用 */
ngx_uint_t connection_n;
ngx_uint_t files_n; // files成员中已介绍
ngx_connection_t *connections; // 当前进程中的所有连接对象
ngx_event_t *read_events; // 当前进程中的所有读事件对象
ngx_event_t *write_events; // 当前进程中的所有写事件对象
/*
* 旧的ngx_cycle_t对象用于引用上一个ngx_cycle_t对象中的成员。
* 举例:ngx_init_cycle方法在启动初期,需要建立一个临时的ngx_cycle_t对象保存一些变量,
* 再调用ngx_init_cycle方法时就可以把旧的ngx_cycle_t传进去,此成员就保存前期的ngx_cycle_t对象
*/
ngx_cycle_t *old_cycle;
ngx_str_t conf_file; // Nginx配置文件相对于安装目录的路径名称
ngx_str_t conf_param; // Nginx处理配置文件时需要特殊处理的在命令行中携带的参数
ngx_str_t conf_prefix; // Nginx配置文件所在目录的路径
ngx_str_t prefix; // Nginx安装目录的路径
ngx_str_t lock_file; // 用于进程间同步的文件锁名称
ngx_str_t hostname; // 使用gethostname系统调用得到的主机名
};
ngx_listening_t结构体
Nginx作为一个Web服务器,首先需要监听端口并处理器中的网络事件,而监听端口这项工作在Nginx的启动框架代码中就已完成。
下面介绍下它的成员:
typedef struct ngx_listening_s ngx_listening_t;
struct ngx_listening_s {
ngx_socket_t fd; // socket句柄
struct sockaddr *sockaddr; // 监听socket地址
socklen_t socklen; // 地址长度
size_t addr_text_max_len; // 存储IP地址的字符串addr_text的最大长度,即指定其所分配的内存大小
ngx_str_t addr_text; // 字符串形式存储的IP地址
int type; // 套接字类型
/* TCP实现监听时的backlog队列,表示允许正在通过三次握手建立TCP连接但没有任何进程开始处理的最大连接数 */
int backlog;
int rcvbuf; // 内核中对于当前套接字的接收缓冲区大小
int sndbuf; // 内核中对于当前套接字的发送缓冲区大小
#if (NGX_HAVE_KEEPALIVE_TUNABLE)
int keepidle;
int keepintvl;
int keepcnt;
#endif
/* handler of accepted connection */
ngx_connection_handler_pt handler; // 新的TCP连接成功建立后的处理方法
/* 保存当前对应着的所有主机名 */
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; // TCP连接建立成功后,经过此成员所对应的时间还没有接收到用户数据,则丢弃连接
ngx_listening_t *previous; // 前一个ngx_listening_t结构,单链表
ngx_connection_t *connection; // 当前监听句柄对应的ngx_connection_t结构体
/* 标志位 */
unsigned open:1; // 置1表示当前监听句柄有效,置0正常关闭
unsigned remain:1; // 置1表示使用已有的ngx_cycle_t来初始化ngx_cycle_t结构,原端口不关闭,置0表示正常关闭端口
unsigned ignore:1; // 置1表示跳过设置当前结构体中套接字成员,置0表示正常初始化套接字
unsigned bound:1; // 置1表示已经绑定,目前未使用
unsigned inherited:1; // 置1表示当前监听句柄来自前一个进程
unsigned nonblocking_accept:1; // 目前未使用
unsigned listen:1; // 置1表示当前结构体的套接字已经在监听
unsigned nonblocking:1; // 表示套接字是否阻塞,目前无意义
unsigned shared:1; // 表示在线程间共享,目前无意义
unsigned addr_ntop:1; // 置1表示Nginx需要将网络地址转变为字符串形式的地址
#if (NGX_HAVE_INET6 && defined IPV6_V6ONLY)
unsigned ipv6only:1;
#endif
unsigned keepalive:2;
#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
};
其中,ngx_connection_handler_pt类型的handler成员在监听端口上成功建立新的TCP连接后,就会回调handler方法,定义如下:
typedef void (*ngx_connection_handler_pt)(ngx_connection_t *c);
它接收一个ngx_connection_t连接参数,许多事件模块都会自定义handler方法。
ngx_cycle_t支持的方法
与ngx_cycle_t核心结构体相关的方式有很多,这里因为我自己还没有接触,只能在这先把与ngx_cycle_t相关的主要方法记录下,在后面的章节中再详细学习,以下方法都在ngx_cycle.c、ngx_process_cycle.c、ngx_event.c文件中。
ngx_cycle_t * ngx_init_cycle(ngx_cycle_t *old_cycle) | 返回初始化成功的完整的ngx_cycle_t结构体,包括初始化ngx_cycle_t中的成员,解析配置文件,加载所有模块,打开监听端口,初始化进程间通信方式等工作。失败则返回NULL指针 |
ngx_int_t ngx_process_options(ngx_cycle_t *cycle) | 用运行Nginx时可能携带的目录参数来初始化cycle,包括初始化运行目录,配置目录,并生成完整的nginx.conf配置文件路径 |
ngx_int_t ngx_add_inherited_sockets(ngx_cycle_t *cycle) | 执行不重启服务升级Nginx时,新的Nginx进程通过此方法使用已经打开的TCP监听端口 |
ngx_int_t ngx_open_listening_sockets(ngx_cycle_t *cycle) | 监听、绑定cycle中的listening动态数组指定的相应端口 |
void ngx_configure_listening_sockets(ngx_cycle_t *cycle) | 根据nginx.conf中的配置项设置已经监听的句柄 |
void ngx_close_listening_sockets(ngx_cycle_t *cycle) | 关闭cycle中的listening动态数组已经打开的端口 |
void ngx_master_process_cycle(ngx_cycle_t *cycle) | 进入master进程的工作循环 |
void ngx_single_process_cycle(ngx_cycle_t *cycle) | 进入单进程模式(非master、worker进程工作模式)的工作循环 |
void ngx_start_worker_processes(ngx_cycle_t *cycle, ngx_int_t n, ngx_int_t type) | 启动n个worker子进程,并设置好每个子进程与master父进程之间使用socketpair系统调用建立起来的socke通信机制。 |
void ngx_start_cache_manager_processes(ngx_cycle_t *cycle, ngx_uint_t respawn) | 根据是否使用文件缓存模块,即cycle中存储路径的动态数组中manager标志是否打开,来决定是否启动cache manager子进程,根据loader标志决定是否启动cache loader进程 |
void ngx_pass_open_channel(ngx_cycle_t *cycle, ngx_channel_t *ch) | 向所有打开的channel发送ch消息 |
void ngx_signal_worker_processes(ngx_cycle_t *cycle, int signo) | 处理worker进程接收到的信号 |
ngx_uint_t ngx_reap_children(ngx_cycle_t *cycle) | 检查master进程的所有子进程,根据每个子进程的状态(ngx_process_t结构体中的标志位)判断是否要启动子进程,更改pid文件等 |
void ngx_master_process_exit(ngx_cycle_t *cycle) | 退出master进程工作的循环 |
void ngx_worker_process_cycle(ngx_cycle_t *cycle, void *data) | 进入worker进程工作的循环 |
void ngx_worker_process_init(ngx_cycle_t *cycle, ngx_int_t worker) | 进入worker进程工作循环之前的初始化工作 |
void ngx_worker_process_exit(ngx_cycle_t *cycle) | 退出worke进程工作的循环 |
void ngx_cache_manager_process_cycle(ngx_cycle_t *cycle, void *data) | 执行缓存管理工作的循环方法 |
void ngx_process_events_and_timers(ngx_cycle_t *cycle) | 使用事件模块处理截止到现在已经收集到的事件 |
总结
全篇就记录一个东西ngx_cycle_t结构体。之后开始Nginx框架启动时的处理流程。
主要参考
《深入理解Nginx》