Nginx学习笔记(十二):核心结构体

前言

继续源码。。。

核心结构

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的启动框架代码中就已完成。

上面ngx_cycle_t对象中有一个动态数组成员叫做listening,它的每个数组元素都是ngx_listening_t结构体。这样的一个结构体表示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》
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值