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

来源:互联网 发布:remind 软件 编辑:程序博客网 时间:2024/05/10 22:39

前言

继续源码。。。

核心结构

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》
0 0