过人科技网

2. 源码讲解2.1 nginx.c主流程对于nginx的启动流程

简介: 2. 源码讲解2.1 nginx.c主流程对于nginx的启动流程,主要是通过调用额各个子流程所封装的方法来实现的,如下是主流程的源码:int ngx_cdecl main(int argc, char *const

如下是main()方法的工作流程:上面的流程图中,容易忽略的一个流程点在于ngx_preinit_modules()方法,该方法中会对各个模块对象的index属性进行初始化,也即将其index设置为其在所有模块数组中的索引下标。

在整个初始化过程中,有一个ngx_init_cycle()方法,该方法是解析配置文件,并且初始化各个模块的核心流程。

如下是该方法的工作流程:从上面的流程可以看出,ngx_init_cycle()方法将配置的初始化分为了几个阶段:创建模块配置对象、解析配置文件、初始化模块配置、创建共享内存块、打开的端口、初始化各个模块。

2. 源码讲解2.1 nginx.c主流程对于nginx的启动流程,主要是通过调用额各个子流程所封装的方法来实现的,如下是主流程的源码:int ngx_cdecl main(int argc, char *const *argv) {ngx_buf_t *b;ngx_log_t *log;ngx_uint_t i;ngx_cycle_t *cycle, init_cycle;ngx_conf_dump_t *cd;ngx_core_conf_t *ccf;ngx_debug_init();// 该方法的具体作用是初始化一个链表,用于存储系统的error日志if(ngx_strerror_init() != NGX_OK) {return1;}// 该方法的主要作用是解析nginx运行时命令行传入的具体参数if(ngx_get_options(argc, argv) != NGX_OK) {return1;}// 显示当前nginx的版本信息if(ngx_show_version) {ngx_show_version_info();// 这里指的是如果不进行配置文件的检测,则直接返回,因为进行配置文件的检测需要对配置文件进行解析,// 因而如果不需要进行解析则直接返回,否则在后续进行配置文件的解析if(!ngx_test_config) {return0;}}/* TODO*/ ngx_max_sockets = -1;// 对nginx缓存的时间信息进行初始化ngx_time_init();#if (NGX_PCRE)// 初始化正则表达式解析所需要的相关函数ngx_regex_init();#endif// 获取当前主进程的idngx_pid = ngx_getpid();// 初始化一个error log的文件句柄log = ngx_log_init(ngx_prefix);if(log == NULL) {return1;}/* STUB */#if (NGX_OPENSSL)ngx_ssl_init(log);#endif/** init_cycle->log is required for signal handlers and* ngx_process_options()*/// 创建一个ngx_cycle_t结构体,这是nginx运行所使用的一个核心结构体,用于在后续存储各种配置信息ngx_memzero(&init_cycle, sizeof(ngx_cycle_t));init_cycle.log = log; // 指定所使用的日志ngx_cycle = &init_cycle; // 将初始化的对象赋值给当前的全局对象// 初始化一块内存池init_cycle.pool = ngx_create_pool(1024, log);if(init_cycle.pool == NULL) {return1;}// 将执行./nginx命令时传入的参数保存到ngx_cycle_t结构体中if(ngx_se_argv(&init_cycle, argc, argv) != NGX_OK) {return1;}// 这里主要是处理nginx的选项值,比如nginx根目录、error log目录和log的日志级别if(ngx_process_options(&init_cycle) != NGX_OK) {return1;}// 这里主要是获取系统的一些参数,比如CPU数目、最大socket数目等if(ngx_os_init(log) != NGX_OK) {return1;}/** ngx_crc32_table_init() requires ngx_cacheline_size set in ngx_os_init()*/// 初始化ngx_crc32_table_short的值为ngx_crc32_table16所指定的值if(ngx_crc32_table_init() != NGX_OK) {return1;}// 这个方法的主要作用是,获取NGINX环境变量的值,将其按照;或者:进行分割,分割后的每一个元素都是一个socket文件描述符的id,// 通过这种方式让当前的nginx继承这些文件描述符,然后会或者这些文件描述符的属性信息,并且将其设置到新创建的ngx_listening_t结构体的对应变量中if(ngx_add_inherited_sockets(&init_cycle) != NGX_OK) {return1;}// 这里主要是对ngx_modules数组中的每个module的index属性进行赋值,通过这种方式指定当前module在整个模块中所在的位置。

// 另外需要注意的是,在每个模块中都有ctx属性,其为一个多维数组,该属性保存了所有模块的配置信息,而当前模块的配置信息也正好在ctx数组的// 对应的位置if(ngx_preinit_modules() != NGX_OK) {return1;}// 这是初始化nginx各个配置的核心方法cycle = ngx_init_cycle(&init_cycle);if(cycle == NULL) {if(ngx_test_config) {ngx_log_stderr(0, "configuration file %s test failed",init_cycle.conf_file.data);}return1;}// 如果是测试模式,则打印配置文件的测试结果,并且如果需要dump配置数据,则进行打印if(ngx_test_config) {if(!ngx_quiet_mode) {ngx_log_stderr(0, "configuration file %s test is successful",cycle->conf_file.data);}if(ngx_dump_config) {cd = cycle->config_dump.elts;for(i = 0; i < cycle->config_dump.nelts; i++) {ngx_write_stdout("# configuration file ");(void) ngx_write_fd(ngx_stdout, cd[i].name.data,cd[i].name.len);ngx_write_stdout(":" NGX_LINEFEED);b = cd[i].buffer;(void) ngx_write_fd(ngx_stdout, b->pos, b->last - b->pos);ngx_write_stdout(NGX_LINEFEED);}}return0;}// 这里的ngx_signal主要是记录了启动参数为-s时,其后面的参数值,比如reload、reopen等if(ngx_signal) {// 这里主要是根据-s后的参数,对当前的master进程发送相应的系统命令returnngx_signal_process(cycle, ngx_signal);}// 这里主要是读取了系统的一些数据,并且打印了出来,没有实际的作用ngx_os_status(cycle->log);ngx_cycle = cycle;ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module);if(ccf->master && ngx_process == NGX_PROCESS_SINGLE) {ngx_process = NGX_PROCESS_MASTER;}#if !(NGX_WIN32)// 这里主要是为各个信号设置其处理函数if(ngx_init_signals(cycle->log) != NGX_OK) {return1;}if(!ngx_inherited && ccf->daemon) {// 如果是daemon模式,则新建一个子进程启动if(ngx_daemon(cycle->log) != NGX_OK) {return1;}ngx_daemonized = 1;}if(ngx_inherited) {ngx_daemonized = 1;}#endif// 重新写入pid到pid文件中,因为daemon模式会新建一个子进程if(ngx_create_pidfile(&ccf->pid, cycle->log) != NGX_OK) {return1;}// 这里主要是将stderr输出指向当前cycle所设置的log文件中if(ngx_log_redirect_stderr(cycle) != NGX_OK) {return1;}if(log->file->fd != ngx_stderr) {if(ngx_close_file(log->file->fd) == NGX_FILE_ERROR) {ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,ngx_close_file_n" built-in log failed");}}ngx_use_stderr = 0;if(ngx_process == NGX_PROCESS_SINGLE) {// 这里是单进程模型,也即的处理、缓存的维护等等工作都交由master进程进行,主要用于调试ngx_single_process_cycle(cycle);} else{// 这里是master-worker进程模型,master负责处理客户端的各种指令,// 并且将相应的指令发送给worker进程进行处理ngx_master_process_cycle(cycle);}return0;}关于最后的master和worker进程的启动流程以及其相互之间的交互方式,我们将在后续的文章中进行讲解。

2.2 ngxinitcycle()分支流程ngx_init_cycle()是nginx初始化过程中不可或缺的一部分,其主要对nginx的启动流程进行了切分,从而实现各个模块定制化配置的切入。

如下是该方法的源码:ngx_cycle_t *ngx_init_cycle(ngx_cycle_t *old_cycle) {void *rv;char **senv;ngx_uint_t i, n;ngx_log_t *log;ngx_time_t *tp;ngx_conf_t conf;ngx_pool_t *pool;ngx_cycle_t *cycle, **old;ngx_shm_zone_t *shm_zone, *oshm_zone;ngx_list_part_t *part, *opart;ngx_open_file_t *file;ngx_listening_t *ls, *nls;ngx_core_conf_t *ccf, *old_ccf;ngx_core_module_t *module;char hostname[NGX_MAXHOSTNAMELEN];// 更新当前缓存的时区信息ngx_timezone_update();/* force localtime update with a new timezone */// 获取缓存的时间tp = ngx_timeofday();tp->sec = 0;// 对缓存的时间进行更新ngx_time_update();log = old_cycle->log;// 创建一个内存池pool = ngx_create_pool(NGX_CYCLE_POOL_SIZE, log);if(pool == NULL) {returnNULL;}pool->log = log;// 创建一个ngx_cycle_t结构体对象cycle = ngx_pcalloc(pool, sizeof(ngx_cycle_t));if(cycle == NULL) {ngx_destroy_pool(pool);returnNULL;}// 设置内存池,日志和旧的cycle对象等属性cycle->pool = pool;cycle->log = log;cycle->old_cycle = old_cycle;// 设置配置文件的信息cycle->conf_prefix.len = old_cycle->conf_prefix.len;cycle->conf_prefix.data = ngx_pstrdup(pool, &old_cycle->conf_prefix);if(cycle->conf_prefix.data == NULL) {ngx_destroy_pool(pool);returnNULL;}// 设置nginx的路径信息cycle->prefix.len = old_cycle->prefix.len;cycle->prefix.data = ngx_pstrdup(pool, &old_cycle->prefix);if(cycle->prefix.data == NULL) {ngx_destroy_pool(pool);returnNULL;}// 设置配置文件的信息cycle->conf_file.len = old_cycle->conf_file.len;cycle->conf_file.data = ngx_pnalloc(pool, old_cycle->conf_file.len + 1);if(cycle->conf_file.data == NULL) {ngx_destroy_pool(pool);returnNULL;}ngx_cpystrn(cycle->conf_file.data, old_cycle->conf_file.data,old_cycle->conf_file.len + 1);cycle->conf_param.len = old_cycle->conf_param.len;cycle->conf_param.data = ngx_pstrdup(pool, &old_cycle->conf_param);if(cycle->conf_param.data == NULL) {ngx_destroy_pool(pool);returnNULL;}n = old_cycle->paths.nelts ? old_cycle->paths.nelts : 10;// 初始化nginx的paths数组if(ngx_array_init(&cycle->paths, pool, n, sizeof(ngx_path_t *))!= NGX_OK) {ngx_destroy_pool(pool);returnNULL;}// 初始化cycle->paths.elts数组长度ngx_memzero(cycle->paths.elts, n * sizeof(ngx_path_t *));// 初始化用于dump配置文件的ngx_conf_dump_t结构体if(ngx_array_init(&cycle->config_dump, pool, 1, sizeof(ngx_conf_dump_t))!= NGX_OK) {ngx_destroy_pool(pool);returnNULL;}// 初始化一个用于dump配置文件的红黑树,其插入操作的方法为ngx_str_rbtree_insert_valuengx_rbtree_init(&cycle->config_dump_rbtree, &cycle->config_dump_sentinel,ngx_str_rbtree_insert_value);// 获取当前打开的文件总数if(old_cycle->open_files.part.nelts) {n = old_cycle->open_files.part.nelts;for(part = old_cycle->open_files.part.next; part; part = part->next) {n += part->nelts;}} else{n = 20;}// 初始化记录打开的文件的链表,默认长度为20if(ngx_list_init(&cycle->open_files, pool, n, sizeof(ngx_open_file_t))!= NGX_OK) {ngx_destroy_pool(pool);returnNULL;}// 计算共享内存的个数if(old_cycle->shared_memory.part.nelts) {n = old_cycle->shared_memory.part.nelts;for(part = old_cycle->shared_memory.part.next; part; part = part->next) {n += part->nelts;}} else{n = 1;}// 初始化存储共享内存信息的链表if(ngx_list_init(&cycle->shared_memory, pool, n, sizeof(ngx_shm_zone_t))!= NGX_OK) {ngx_destroy_pool(pool);returnNULL;}// 获取的socket的数目n = old_cycle->listening.nelts ? old_cycle->listening.nelts : 10;// 初始化用于存储的socket的数组if(ngx_array_init(&cycle->listening, pool, n, sizeof(ngx_listening_t))!= NGX_OK) {ngx_destroy_pool(pool);returnNULL;}// 初始化用于存储的socket的数组元素ngx_memzero(cycle->listening.elts, n * sizeof(ngx_listening_t));// 初始化用于存储可服用的connection的队列ngx_queue_init(&cycle->reusable_connections_queue);// 初始化用于存储各个模块配置信息的对象cycle->conf_ctx = ngx_pcalloc(pool, ngx_max_module * sizeof(void *));if(cycle->conf_ctx == NULL) {ngx_destroy_pool(pool);returnNULL;}// 获取当前的hostnameif(gethostname(hostname, NGX_MAXHOSTNAMELEN) == -1) {ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, "gethostname() failed");ngx_destroy_pool(pool);returnNULL;}/* on Linux gethostname() silently truncates name that does not fit */hostname[NGX_MAXHOSTNAMELEN - 1] = '\0';cycle->hostname.len = ngx_strlen(hostname);// 申请用于存储hostname的内存空间cycle->hostname.data = ngx_pnalloc(pool, cycle->hostname.len);if(cycle->hostname.data == NULL) {ngx_destroy_pool(pool);returnNULL;}// 将获取到的hostname转换为小写,然后存储到cycle->hostname.data中ngx_strlow(cycle->hostname.data, (u_char *) hostname, cycle->hostname.len);// 将获ngx_modules数组复制到cycle->modules数组中if(ngx_cycle_modules(cycle) != NGX_OK) {ngx_destroy_pool(pool);returnNULL;}for(i = 0; cycle->modules[i]; i++) {// 找到nginx的核心模块if(cycle->modules[i]->type != NGX_CORE_MODULE) {continue;}module = cycle->modules[i]->ctx;// 这里主要是初始化各个模块的配置对象的结构体。

首先判断各个模块的create_conf()方法是否存在,如果存在,则调用该方法// 创建对应的conf结构体,然后将其赋值到cycle->conf_ctx的对应索引位置。

// 需要注意的是,这里创建的配置对象结构体的属性值都是默认值,其并没有初始化if(module->create_conf) {rv = module->create_conf(cycle);if(rv == NULL) {ngx_destroy_pool(pool);returnNULL;}cycle->conf_ctx[cycle->modules[i]->index] = rv;}}senv = environ;// 创建一个用于存储配置信息的结构体,并且初始化各个参数信息ngx_memzero(&conf, sizeof(ngx_conf_t));/* STUB: init array ? */conf.args = ngx_array_create(pool, 10, sizeof(ngx_str_t));if(conf.args == NULL) {ngx_destroy_pool(pool);returnNULL;}conf.temp_pool = ngx_create_pool(NGX_CYCLE_POOL_SIZE, log);if(conf.temp_pool == NULL) {ngx_destroy_pool(pool);returnNULL;}conf.ctx = cycle->conf_ctx;conf.cycle = cycle;conf.pool = pool;conf.log = log;conf.module_type = NGX_CORE_MODULE;conf.cmd_type = NGX_MAIN_CONF;#if 0log->log_level = NGX_LOG_DEBUG_ALL;#endifif(ngx_conf_param(&conf) != NGX_CONF_OK) {environ = senv;ngx_destroy_cycle_pools(&conf);returnNULL;}// 这里主要是对配置文件进行解析if(ngx_conf_parse(&conf, &cycle->conf_file) != NGX_CONF_OK) {environ = senv;ngx_destroy_cycle_pools(&conf);returnNULL;}// 如果当前执行的./nginx命令后是-t参数,并且当前不是静态模式,则打印配置文件的解析结果if(ngx_test_config && !ngx_quiet_mode) {ngx_log_stderr(0, "the configuration file %s syntax is ok",cycle->conf_file.data);}for(i = 0; cycle->modules[i]; i++) {if(cycle->modules[i]->type != NGX_CORE_MODULE) {continue;}module = cycle->modules[i]->ctx;// 这里主要是初始化核心模块的配置信息// 对于核心模块,目前主要有core、errlog、regex和events这四个,这里的init_conf()方法主要是对这些模块的配置对象中的数据// 设置默认值,因为定制化的值在前面的配置文件的解析过程中已经进行了设置if(module->init_conf) {if(module->init_conf(cycle,cycle->conf_ctx[cycle->modules[i]->index])== NGX_CONF_ERROR) {environ = senv;ngx_destroy_cycle_pools(&conf);returnNULL;}}}if(ngx_process == NGX_PROCESS_SIGNALLER) {returncycle;}// 获取ngx_core_module的配置对象ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module);// 如果是测试模式,则创建对应的pid文件if(ngx_test_config) {// 创建存储了pid的文件if(ngx_create_pidfile(&ccf->pid, log) != NGX_OK) {gotofailed;}// 检查如果不是初始化cycle对象,则创建一个pid文件,并且删除旧的pid文件} elseif(!ngx_is_init_cycle(old_cycle)) {/** we do not create the pid file in the first ngx_init_cycle() call* because we need to write the demonized process pid*/old_ccf = (ngx_core_conf_t *) ngx_get_conf(old_cycle->conf_ctx,ngx_core_module);if(ccf->pid.len != old_ccf->pid.len|| ngx_strcmp(ccf->pid.data, old_ccf->pid.data) != 0) {/* new pid file name */if(ngx_create_pidfile(&ccf->pid, log) != NGX_OK) {gotofailed;}ngx_delete_pidfile(old_cycle);}}// 这里主要是检查lock file是否有操作的权限if(ngx_test_lockfile(cycle->lock_file.data, log) != NGX_OK) {gotofailed;}// 这里主要是检查配置的各个文件路径是否存在,如果不存在就创建该文件夹,并且检查当前用户是否有相应的操作权限,// 如果权限不够,则提升当前用户的操作权限if(ngx_create_paths(cycle, ccf->user) != NGX_OK) {gotofailed;}// 这里主要是如果没有指定error log文件地址,则打开一个默认的error日志配置文件if(ngx_log_open_default(cycle) != NGX_OK) {gotofailed;}/* open the new files */part = &cycle->open_files.part;file = part->elts;for(i = 0; /* void */ ; i++) {if(i >= part->nelts) {if(part->next == NULL) {break;}part = part->next;file = part->elts;i = 0;}if(file[i].name.len == 0) {continue;}// 打开指定的文件,比如access log等file[i].fd = ngx_open_file(file[i].name.data,NGX_FILE_APPEND,NGX_FILE_CREATE_OR_OPEN,NGX_FILE_DEFAULT_ACCESS);ngx_log_debug3(NGX_LOG_DEBUG_CORE, log, 0,"log: %p %d \"%s\"",&file[i], file[i].fd, file[i].name.data);if(file[i].fd == NGX_INVALID_FILE) {ngx_log_error(NGX_LOG_EMERG, log, ngx_errno,ngx_open_file_n" \"%s\" failed",file[i].name.data);gotofailed;}#if !(NGX_WIN32)// 这里主要是为创建的文件设置关闭的,即当前进程退出时关闭该文件if(fcntl(file[i].fd, F_SETFD, FD_CLOEXEC) == -1) {ngx_log_error(NGX_LOG_EMERG, log, ngx_errno,"fcntl(FD_CLOEXEC) \"%s\" failed",file[i].name.data);gotofailed;}#endif}cycle->log = &cycle->new_log;pool->log = &cycle->new_log;/* create shared memory */part = &cycle->shared_memory.part;shm_zone = part->elts;for(i = 0; /* void */ ; i++) {if(i >= part->nelts) {if(part->next == NULL) {break;}part = part->next;shm_zone = part->elts;i = 0;}if(shm_zone[i].shm.size == 0) {ngx_log_error(NGX_LOG_EMERG, log, 0,"zero size shared memory zone \"%V\"",&shm_zone[i].shm.name);gotofailed;}shm_zone[i].shm.log = cycle->log;opart = &old_cycle->shared_memory.part;oshm_zone = opart->elts;for(n = 0; /* void */ ; n++) {if(n >= opart->nelts) {if(opart->next == NULL) {break;}opart = opart->next;oshm_zone = opart->elts;n = 0;}if(shm_zone[i].shm.name.len != oshm_zone[n].shm.name.len) {continue;}if(ngx_strncmp(shm_zone[i].shm.name.data,oshm_zone[n].shm.name.data,shm_zone[i].shm.name.len)!= 0) {continue;}// 这里的三个if判断主要是找到当前的共享内存与旧的cycle中的共享内存名称和大小等完全一致时,直接复用旧的共享内存if(shm_zone[i].tag == oshm_zone[n].tag&& shm_zone[i].shm.size == oshm_zone[n].shm.size&& !shm_zone[i].noreuse) {shm_zone[i].shm.addr = oshm_zone[n].shm.addr;#if (NGX_WIN32)shm_zone[i].shm.handle = oshm_zone[n].shm.handle;#endif// 复用之后,对旧的共享内存进行重新初始化if(shm_zone[i].init(&shm_zone[i], oshm_zone[n].data)!= NGX_OK) {gotofailed;}gotoshm_zone_found;}// 如果没找到,则释放旧的共享内存ngx_shm_free(&oshm_zone[n].shm);break;}// 走到这里,说明没有可复用的旧的共享内存,则为当前的共享内存重新申请内存if(ngx_shm_alloc(&shm_zone[i].shm) != NGX_OK) {gotofailed;}// 这里主要是初始化共享内存的内存池信息if(ngx_init_zone_pool(cycle, &shm_zone[i]) != NGX_OK) {gotofailed;}// 初始化新申请的共享内存if(shm_zone[i].init(&shm_zone[i], NULL) != NGX_OK) {gotofailed;}shm_zone_found:continue;}/* handle the listening sockets */if(old_cycle->listening.nelts) {ls = old_cycle->listening.elts;for(i = 0; i < old_cycle->listening.nelts; i++) {ls[i].remain = 0;}nls = cycle->listening.elts;for(n = 0; n < cycle->listening.nelts; n++) {for(i = 0; i < old_cycle->listening.nelts; i++) {if(ls[i].ignore) {continue;}// 前面已经置为了0,因而不会走到if块中if(ls[i].remain) {continue;}if(ls[i].type != nls[n].type) {continue;}if(ngx_cmp_sockaddr(nls[n].sockaddr, nls[n].socklen,ls[i].sockaddr, ls[i].socklen, 1)== NGX_OK) {// 这里主要是复用旧的的文件句柄nls[n].fd = ls[i].fd;nls[n].previous = &ls[i];ls[i].remain = 1;// 如果新的ngx_listening_sacklog队列大小不等于旧acklog队列大小,这将其listen字段设置为1,// listen字段的含义主要是表征当前句柄正在被if(ls[i].backlog != nls[n].backlog) {nls[n].listen = 1;}// 这里主要是设置新的的ngx_listening_s结构体的deferred_accept和accept_filter属性,在TCP数据传输时,// 如果设置了deferred_accept,那么在进行TCP三次握手之前,只有在真正接收到客户端数据之后,才会将客户端连接从backlog队列移// 到accept队列中,从而交由NGINX处理,这样可以大大减少nginx的资源消耗#if (NGX_HE_DEFERRED_ACCEPT && defined SO_ACCEPTFILTER)/** FreeBSD, except the most recent versions,* could not remove accept filter*/nls[n].deferred_accept = ls[i].deferred_accept;if(ls[i].accept_filter && nls[n].accept_filter) {if(ngx_strcmp(ls[i].accept_filter,nls[n].accept_filter)!= 0){nls[n].delete_deferred = 1;nls[n].add_deferred = 1;}} elseif(ls[i].accept_filter) {nls[n].delete_deferred = 1;} elseif(nls[n].accept_filter) {nls[n].add_deferred = 1;}#endif#if (NGX_HE_DEFERRED_ACCEPT && defined TCP_DEFER_ACCEPT)if(ls[i].deferred_accept && !nls[n].deferred_accept) {nls[n].delete_deferred = 1;} elseif(ls[i].deferred_accept != nls[n].deferred_accept){nls[n].add_deferred = 1;}#endif// 设置reuseport属性值#if (NGX_HE_REUSEPORT)if(nls[n].reuseport && !ls[i].reuseport) {nls[n].add_reuseport = 1;}#endifbreak;}}if(nls[n].fd == (ngx_socket_t) -1) {nls[n].open = 1;#if (NGX_HE_DEFERRED_ACCEPT && defined SO_ACCEPTFILTER)if(nls[n].accept_filter) {nls[n].add_deferred = 1;}#endif#if (NGX_HE_DEFERRED_ACCEPT && defined TCP_DEFER_ACCEPT)if(nls[n].deferred_accept) {nls[n].add_deferred = 1;}#endif}}} else{ls = cycle->listening.elts;for(i = 0; i < cycle->listening.nelts; i++) {ls[i].open = 1;#if (NGX_HE_DEFERRED_ACCEPT && defined SO_ACCEPTFILTER)if(ls[i].accept_filter) {ls[i].add_deferred = 1;}#endif#if (NGX_HE_DEFERRED_ACCEPT && defined TCP_DEFER_ACCEPT)if(ls[i].deferred_accept) {ls[i].add_deferred = 1;}#endif}}// 这里主要是打开各个的端口if(ngx_open_listening_sockets(cycle) != NGX_OK) {gotofailed;}if(!ngx_test_config) {// 这里主要是为各个套接字设置TCP相关的一些属性ngx_configure_listening_sockets(cycle);}/* commit the new cycle configuration */if(!ngx_use_stderr) {(void) ngx_log_redirect_stderr(cycle);}pool->log = cycle->log;// 这里调用各个模块的init_module()方法对当前模块进行初始化if(ngx_init_modules(cycle) != NGX_OK) {/* fatal */exit(1);}/* close and delete stuff that lefts from an old cycle *//* free the unnecessary shared memory */opart = &old_cycle->shared_memory.part;oshm_zone = opart->elts;for(i = 0; /* void */ ; i++) {if(i >= opart->nelts) {if(opart->next == NULL) {gotoold_shm_zone_done;}opart = opart->next;oshm_zone = opart->elts;i = 0;}part = &cycle->shared_memory.part;shm_zone = part->elts;for(n = 0; /* void */ ; n++) {if(n >= part->nelts) {if(part->next == NULL) {break;}part = part->next;shm_zone = part->elts;n = 0;}if(oshm_zone[i].shm.name.len == shm_zone[n].shm.name.len&& ngx_strncmp(oshm_zone[i].shm.name.data,shm_zone[n].shm.name.data,oshm_zone[i].shm.name.len)== 0) {gotolive_shm_zone;}}// 这里主要是将旧的共享内存释放掉ngx_shm_free(&oshm_zone[i].shm);live_shm_zone:continue;}old_shm_zone_done:/* close the unnecessary listening sockets */ls = old_cycle->listening.elts;for(i = 0; i < old_cycle->listening.nelts; i++) {if(ls[i].remain || ls[i].fd == (ngx_socket_t) -1) {continue;}// 将旧的的套接字关闭调if(ngx_close_socket(ls[i].fd) == -1) {ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno,ngx_close_socket_n" listening socket on %V failed",&ls[i].addr_text);}#if (NGX_HE_UNIX_DOMAIN)if(ls[i].sockaddr->sa_family == AF_UNIX) {u_char *name;name = ls[i].addr_text.data + sizeof("unix:") - 1;ngx_log_error(NGX_LOG_WARN, cycle->log, 0,"deleting socket %s", name);if(ngx_delete_file(name) == NGX_FILE_ERROR) {ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_socket_errno,ngx_delete_file_n" %s failed", name);}}#endif}/* close the unnecessary open files */part = &old_cycle->open_files.part;file = part->elts;for(i = 0; /* void */ ; i++) {if(i >= part->nelts) {if(part->next == NULL) {break;}part = part->next;file = part->elts;i = 0;}if(file[i].fd == NGX_INVALID_FILE || file[i].fd == ngx_stderr) {continue;}// 将旧的无效的文件路径描述符关掉if(ngx_close_file(file[i].fd) == NGX_FILE_ERROR) {ngx_log_error(NGX_LOG_EMERG, log, ngx_errno,ngx_close_file_n" \"%s\" failed",file[i].name.data);}}// 销毁临时内存池ngx_destroy_pool(conf.temp_pool);if(ngx_process == NGX_PROCESS_MASTER || ngx_is_init_cycle(old_cycle)) {ngx_destroy_pool(old_cycle->pool);cycle->old_cycle = NULL;returncycle;}if(ngx_temp_pool == NULL) {ngx_temp_pool = ngx_create_pool(128, cycle->log);if(ngx_temp_pool == NULL) {ngx_log_error(NGX_LOG_EMERG, cycle->log, 0,"could not create ngx_temp_pool");exit(1);}n = 10;if(ngx_array_init(&ngx_old_cycles, ngx_temp_pool, n,sizeof(ngx_cycle_t *))!= NGX_OK) {exit(1);}ngx_memzero(ngx_old_cycles.elts, n * sizeof(ngx_cycle_t *));// 清理旧的cycle对象,清理方式主要是将其放到队列中定时进行清理ngx_cleaner_event.handler = ngx_clean_old_cycles;ngx_cleaner_event.log = cycle->log;ngx_cleaner_event.data = &dumb;dumb.fd = (ngx_socket_t) -1;}ngx_temp_pool->log = cycle->log;old = ngx_array_push(&ngx_old_cycles);if(old == NULL) {exit(1);}*old = old_cycle;if(!ngx_cleaner_event.timer_set) {ngx_add_timer(&ngx_cleaner_event, 30000);ngx_cleaner_event.timer_set = 1;}returncycle;failed:if(!ngx_is_init_cycle(old_cycle)) {old_ccf = (ngx_core_conf_t *) ngx_get_conf(old_cycle->conf_ctx,ngx_core_module);if(old_ccf->environment) {environ = old_ccf->environment;}}/* rollback the new cycle configuration */part = &cycle->open_files.part;file = part->elts;for(i = 0; /* void */ ; i++) {if(i >= part->nelts) {if(part->next == NULL) {break;}part = part->next;file = part->elts;i = 0;}if(file[i].fd == NGX_INVALID_FILE || file[i].fd == ngx_stderr) {continue;}// 关闭文件路径描述符if(ngx_close_file(file[i].fd) == NGX_FILE_ERROR) {ngx_log_error(NGX_LOG_EMERG, log, ngx_errno,ngx_close_file_n" \"%s\" failed",file[i].name.data);}}if(ngx_test_config) {ngx_destroy_cycle_pools(&conf);returnNULL;}ls = cycle->listening.elts;for(i = 0; i < cycle->listening.nelts; i++) {if(ls[i].fd == (ngx_socket_t) -1 || !ls[i].open) {continue;}// 关闭的套接字句柄if(ngx_close_socket(ls[i].fd) == -1) {ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno,ngx_close_socket_n" %V failed",&ls[i].addr_text);}}ngx_destroy_cycle_pools(&conf);returnNULL;}3. 小结本文首先对nginx的主流程和ngx_init_cycle()配置流程的工作原理进行了讲解,然后从源码层面对这两个流程进行了深入分析。


以上是文章"

2. 源码讲解2.1 nginx.c主流程对于nginx的启动流程

"的内容,欢迎阅读过人科技网的其它文章