搭建nginx服务器时,主要的配置文件 nginx.conf 是部署和维护服务器人员经常要使用到的文件, 里面进行了许多服务器参数的设置。那么nginx 以模块 module为骨架的设计下是如何运用模块 module来解析并执行nginx.conf配置文件下的指令的呢?在探究源码之前,需要对nginx下的模块 module 有个基本的认知(详情参考前面的博文  Nginx 源码分析-- 浅谈对模块module 的基本认知 )同时也要对nginx中常用到的一些结构有个基本的了解如: 内存池pool 管理相关的函数、ngx_string 的基本结构等(详情参考前面的博文),若不然看代码的时候可能不能很明晰其中的意思,本文着重探究的是解析执行的流程。

  1、从main函数说起。

  Nginx的main函数在nginx.c文件中(本文使用release-1.3.0版本源码 ,200行),因为是主函数其中涉及到了许许多多的功能模块的初始化等内容,我们只关注我们需要的部分。看到326行:

    ngx_max_module = 0;for (i = 0; ngx_modules[i]; i++) {ngx_modules[i]->index = ngx_max_module++;}

  cycle = ngx_init_cycle(&init_cycle);

  可以看出来,这里对 ngx_modules ( Nginx 源码分析-- 浅谈对模块module 的基本认知 中有介绍)进行了索引编号,并且计算得到模块的总数 ngx_max_module。然后,对cycle进行初始化,跳转到 ngx_init_cycle中。对于cycle 这个变量是nginx的核心变量,可以说模块机制都是围绕它进行的,里面的参数比较复杂涉及到的内容十分多,本文并不详细对它讨论,可以将其看作是一个核心资源库。

  2、ngx_init_cycle 函数

  这个函数在文件ngx_cycle.c中(43行),这个函数是nginx初始化中最重要的函数之一,里面涉及到与cycle变量相关的初始化工作,看到第188行

 cycle->conf_ctx = ngx_pcalloc(pool, ngx_max_module * sizeof(void *));

  这里获取了 ngx_max_module 个指针空间,用来保存每个模块的配置信息,从cycle 变量的字段conf_ctx 命名中就可以知道,ctx 为context 上下文的缩写。接下来看到,下面这段:

for (i = 0; ngx_modules[i]; i++) {if (ngx_modules[i]->type != NGX_CORE_MODULE) {continue;}module = ngx_modules[i]->ctx;if (module->create_conf) {rv = module->create_conf(cycle);if (rv == NULL) {ngx_destroy_pool(pool);return NULL;} cycle->conf_ctx[ngx_modules[i]->index] = rv;}}

  意思就是获取模块中属于 NGX_CORE_MODULE 类的模块,如果需要创建配置信息就创建相应的配置信息,并且将地址保存在先前创建好的 cycle->conf_ctx 地址空间中,完成核心模块配置文件的创建过程,至此前期工作就基本完成了。

    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);return NULL;}if (ngx_conf_parse(&conf, &cycle->conf_file) != NGX_CONF_OK) {environ = senv;ngx_destroy_cycle_pools(&conf);return NULL;}

  前面conf的赋值那段,无非是对conf进行些必要的初始化。注意一下这里解析的都是对核心模块进行的,创建的配置文件也只是核心模块。关键的函数开始出现了:ngx_conf_param(&conf) 将conf需要的参数(可能没有就是空)存到conf中,ngx_conf_parse(&conf, &cycle->conf_file) 解析配置文件!

  3、函数ngx_conf_parse 指令解析函数,关键函数!

char *
ngx_conf_parse(ngx_conf_t *cf, ngx_str_t *filename)
{char             *rv;ngx_fd_t          fd;ngx_int_t         rc;ngx_buf_t         buf;ngx_conf_file_t  *prev, conf_file;enum {parse_file = 0,parse_block,parse_param} type;
/*  该函数存在三种运行方式,并非一定需要打开配置文件*/
#if (NGX_SUPPRESS_WARN)fd = NGX_INVALID_FILE;prev = NULL;
#endif
/*  filename 的值为 nginx.conf 的路径
*/if (filename) {/* 打开配置文件 */fd = ngx_open_file(filename->data, NGX_FILE_RDONLY, NGX_FILE_OPEN, 0);   ... /*      保存cf->conf_file 的上文    */ prev = cf->conf_file;    /*      定义cf->conf_file 当前的变量信息     */  cf->conf_file = &conf_file;        /*        接下来是对,conf_file 的参数进行设置,为了方便阅读省略此处代码      */

      ...     /*        将函数的运行模式定位为 parse_file ,配置文件模式。      */type = parse_file;      /*        其它两个else 是定义其他模式,在解析nginx.conf时并不会使用到      */} else if (cf->conf_file->file.fd != NGX_INVALID_FILE) {type = parse_block;} else {type = parse_param;} /*    完成对配置文件信息的,初步设置之后,就开始对配置文件进行解析。  */for ( ;; ) {    /*        获取从配置文件nginx.conf中读取的指令名,对于 ngx_conf_read_token 下面给出来返回参数的详细英文注释
    */rc = ngx_conf_read_token(cf);/** ngx_conf_read_token() may return**    NGX_ERROR             there is error*    NGX_OK                the token terminated by ";" was found*    NGX_CONF_BLOCK_START  the token terminated by "{" was found*    NGX_CONF_BLOCK_DONE   the "}" was found*    NGX_CONF_FILE_DONE    the configuration file is done*/     /*      如果错误,调转到done处执行      */if (rc == NGX_ERROR) {goto done;}      /*        如果如到“}”符号,跳转到done处执行,出现错误跳到failed处      */if (rc == NGX_CONF_BLOCK_DONE) {if (type != parse_block) {ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "unexpected \"}\"");goto failed;}goto done;}    /*      如果配置文件全部解析完成,调转到done处执行。    */if (rc == NGX_CONF_FILE_DONE) {if (type == parse_block) {ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,"unexpected end of file, expecting \"}\"");goto failed;}goto done;}      /*        如果遇到“{"但出现错误,调转到failed 处执行      */if (rc == NGX_CONF_BLOCK_START) {if (type == parse_param) {ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,"block directives are not supported ""in -g option");goto failed;}}/*      前面对可能出现的情况都进行了相应的跳转,那么剩下的就是读取 指令正确后执行的过程了,主要分为两种,一种为NGX_OK 一般指令的进行如:worker_processes       另一种 NGX_CONF_BLOCK_START 就是以{作为结束符指令的执行,如:events、http 这类有二级指令的。
      rc == NGX_OK || rc == NGX_CONF_BLOCK_START       */if (cf->handler) {/*        指令执行前是否要进行些处理工作* the custom handler, i.e., that is used in the http's* "types { ... }" directive*/rv = (*cf->handler)(cf, NULL, cf->handler_conf);if (rv == NGX_CONF_OK) {continue;}if (rv == NGX_CONF_ERROR) {goto failed;}ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, rv);goto failed;}/*      下一个关键函数 ngx_conf_handler    */rc = ngx_conf_handler(cf, rc);if (rc == NGX_ERROR) {goto failed;}}failed:rc = NGX_ERROR;done:    /*    一些完成后的处理,释放资源或者 出错处理。省略    */   ...
    /*      恢复上下文    */   cf->conf_file = prev;}if (rc == NGX_ERROR) {return NGX_CONF_ERROR;}return NGX_CONF_OK;
}

  在以上代码中,除了将关键函数用红色标记以外,还特意将 函数中 对上下文的保存和还原 工作的地方进行了红色标记,因为在nginx源码中经常使用到这种机制,可以记住下这样的写法。

  4、函数ngx_conf_handler 指令处理函数,关键函数!

static ngx_int_t
ngx_conf_handler(ngx_conf_t *cf, ngx_int_t last)
{  ...    for (i = 0; ngx_modules[i]; i++) {/* 查找与指令想对应的模块 module*/if (ngx_modules[i]->type != NGX_CONF_MODULE&& ngx_modules[i]->type != cf->module_type){continue;} /*        读取模块的指令集      */cmd = ngx_modules[i]->commands;if (cmd == NULL) {continue;}for ( /* void */ ; cmd->name.len; cmd++) { /*          遍历指令集中的指令,并找寻 从配置文件中读取到的 指令相对应的 内容        */if (name->len != cmd->name.len) {continue;}if (ngx_strcmp(name->data, cmd->name.data) != 0) {continue;}/* 判断下指令类型  是否正确*/if (!(cmd->type & cf->cmd_type)) {if (cmd->type & NGX_CONF_MULTI) {multi = 1;continue;}goto not_allowed;}        ...

      /*判断指令参数是否正确*/if (!(cmd->type & NGX_CONF_ANY)) {if (cmd->type & NGX_CONF_FLAG) {if (cf->args->nelts != 2) {goto invalid;}} else if (cmd->type & NGX_CONF_1MORE) {         }          ...}/*

        通过指令的类型,来设置执行指令时需要的 模块前期创建的 cf_ctx里面的配置信息,朔源就是 cycle->conf_ctx 当然它指向的 上下文 可能已经发生了改变
        */         conf = NULL;        if (cmd->type & NGX_DIRECT_CONF) { conf = ((void **) cf->ctx)[ngx_modules[i]->index]; }           ...  /*        执行指令对应的  功能函数!!        */rv = cmd->set(cf, cmd, conf);

        /*

          如果执行成功,返回 成功。

        */

        if (rv == NGX_CONF_OK) {
          return NGX_OK;
         }

        /*          至此,配置文件的指令执行就结束了。后面都是一些出错处理,在此省略。        */  ...}} ...
}

  写到这里时间已经有些晚了,小结一下。通过代码摘录的介绍,将整个nginx.conf解析的流程 概括的演示了出来,对于其中的些地方可能还不明晰如:二级模块的指令是如何执行的(就是 events{ ... }、http{ ... } 括号里面的指令如何执行的)、非核心模块是如何加入对 nginx.conf 这个配置文件进行解析 等一些内容,在后面的分析中再写吧。晚安!

转载于:https://www.cnblogs.com/jzhlin/archive/2012/06/18/nginx_conf_1.html

Nginx 源码分析-- 模块module 解析执行 nginx.conf 配置文件流程分析 一相关推荐

  1. 【Linux后台开发系列】Nginx源码从模块开发开始,不再对nginx源码陌生丨源码分析

    Nginx源码从模块开发开始,不再对nginx源码发怵,值得学习,认真听完. 1.  nginx的conf配置,cmd解析 2.  nginx模块的八股文 3.  nginx开发的细枝末节 [Linu ...

  2. Nginx源码从模块开发入手,3个项目弄透nginx模块开发丨Linux服务器开发丨C++后端开发丨中间件开发丨分布式丨web服务器

    Nginx源码从模块开发入手,3个项目弄透nginx模块开发 1. Nginx http请求的11个处理流程 2. Upstream, Filter,Handler模块分析 3. nginx如何拒绝无 ...

  3. nginx 源码学习笔记(二)——nginx精粹-模块

    看了一点nginx的源码发现,nginx的模块思想确实吸引了我,也不得不佩服俄罗斯人的想问题方式,要分析nginx源码,首先要搞懂的就是nginx的模块思想以及相关的数据结构. 还记得我们上一次写的h ...

  4. [nginx源码]FastCGI模块详解

    目录 1.初识FastCGI协议 1.1消息头 1.2消息体举例 2. 基础知识 2.1 FastCGI配置 2.2FastCGI配置预处理 3.构造FastCGI请求 3.1FastCGI请求结构 ...

  5. Nginx源码研究三:Epoll在NGINX中的使用

    Web服务器在面对高并发的情况下,网络的IO一般选择IO复用,像apache选择的Select/poll.Nginx在linux 2.6后选择Epoll做网路IO,提高了WEB服务的并发能力. 在本章 ...

  6. Nginx源码安装及调优配置

    由于Nginx本身的一些优点,轻量,开源,易用,越来越多的公司使用nginx作为自己公司的web应用服务器,本文详细介绍nginx源码安装的同时并对nginx进行优化配置. Nginx编译前的优化 [ ...

  7. Nginx 源码编译

    1.首先在官网下载Nginx 发布版的源码, Nginx 官网下载的地址是 :http://www.nginx.org/en/download.html 因为Nginx官网支持SVN,可以简单方便的使 ...

  8. 如何高效的学习 Nginx 源码,汲取养分?

    Nginx 的功能点比较多,涉及到的新概念和设计思路对于新手也不是特别友好,我建议在了解一些了 Nginx 的一些基础知识之后,通过调试来学习 Nginx 源码. 以下操作需要一些 gdb 调试知识, ...

  9. linux安装nginx源码,CentOS7源码编译安装Nginx

    一.安装步骤 1.下载 nginx 源码包 官网$ wget http://nginx.org/download/nginx-1.16.0.tar.gz 2.解压 nginx 压缩包$ tar -zx ...

最新文章

  1. 一步一步指引你在Windows7上配置编译使用Caffe(https://github.com/fengbingchun/Caffe_Test)
  2. activiti自己定义流程之Spring整合activiti-modeler5.16实例(四):部署流程定义
  3. 深度学习Pytorch框架Tensor张量
  4. 防止酒后删库!日本人用 3 小时做了个酒精测试软件
  5. Select 多个表并且相关联转置
  6. CET6级高频词(按频度)(700个)
  7. 给我的宏基上网本用U盘装XP系统
  8. 记OC迁移至swift中笔记20tips
  9. listview复用机制研究
  10. sphinx php mysql_Sphinx+MySQL+PHP 12亿DNS数据秒查
  11. jquery foreach循环
  12. 两个网段共享打印机_不同ip段共享打印机设置方法
  13. echart报错echarts/lib/visual/dataColor in ./node_modules/echarts-liquidfill/src/liquidFill.js
  14. 发射瞬时速度约束下的弹道导弹轨迹仿真算法
  15. ECHAP:身份认证的安全协议
  16. 如何用c语言计算三角形面积
  17. 一文带你快速入门【哈希表】
  18. Android两种时间轴实现
  19. java-UTC时间戳格式化成年月日,UTC时间戳转成北京时间并格式化年月日
  20. C语言之程序在内存中的分布以及内存越界问题

热门文章

  1. 清华大学郑莉c++答疑
  2. 生命游戏(Game of Life)描述
  3. 先写ppt,再写报告,在做实验是一个不错的方法!
  4. 毕业的答辩需要的要求(从校方的角度)
  5. convex function
  6. AnimatorController即动画控制器创建的BUG
  7. iOS Sharing #02 | 2019-03-30
  8. Python 字典 fromkeys()方法
  9. Git undo 操作
  10. 在tomcat中使用context节点部署工程