日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > Nginx >内容正文

Nginx

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

發(fā)布時間:2025/3/15 Nginx 39 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Nginx 源码分析-- 模块module 解析执行 nginx.conf 配置文件流程分析 一 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

  搭建nginx服務器時,主要的配置文件 nginx.conf 是部署和維護服務器人員經(jīng)常要使用到的文件, 里面進行了許多服務器參數(shù)的設置。那么nginx 以模塊 module為骨架的設計下是如何運用模塊 module來解析并執(zhí)行nginx.conf配置文件下的指令的呢?在探究源碼之前,需要對nginx下的模塊 module 有個基本的認知(詳情參考前面的博文 ?Nginx 源碼分析-- 淺談對模塊module 的基本認知?)同時也要對nginx中常用到的一些結構有個基本的了解如: 內(nèi)存池pool 管理相關的函數(shù)、ngx_string 的基本結構等(詳情參考前面的博文),若不然看代碼的時候可能不能很明晰其中的意思,本文著重探究的是解析執(zhí)行的流程。

  1、從main函數(shù)說起。

  Nginxmain函數(shù)在nginx.c文件中(本文使用release-1.3.0版本源碼 ,200行),因為是主函數(shù)其中涉及到了許許多多的功能模塊的初始化等內(nèi)容,我們只關注我們需要的部分??吹?/span>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 的基本認知?中有介紹)進行了索引編號,并且計算得到模塊的總數(shù) ngx_max_module。然后,對cycle進行初始化,跳轉(zhuǎn)到 ngx_init_cycle中。對于cycle 這個變量是nginx的核心變量,可以說模塊機制都是圍繞它進行的,里面的參數(shù)比較復雜涉及到的內(nèi)容十分多,本文并不詳細對它討論,可以將其看作是一個核心資源庫。

  2、ngx_init_cycle 函數(shù)

  這個函數(shù)在文件ngx_cycle.c中(43行),這個函數(shù)是nginx初始化中最重要的函數(shù)之一,里面涉及到與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 類的模塊,如果需要創(chuàng)建配置信息就創(chuàng)建相應的配置信息,并且將地址保存在先前創(chuàng)建好的 cycle->conf_ctx 地址空間中,完成核心模塊配置文件的創(chuàng)建過程,至此前期工作就基本完成了。

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進行些必要的初始化。注意一下這里解析的都是對核心模塊進行的,創(chuàng)建的配置文件也只是核心模塊。關鍵的函數(shù)開始出現(xiàn)了:ngx_conf_param(&conf) conf需要的參數(shù)(可能沒有就是空)存到conf中,ngx_conf_parse(&conf, &cycle->conf_file) 解析配置文件!

  3、函數(shù)ngx_conf_parse 指令解析函數(shù),關鍵函數(shù)!

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; /*
  該函數(shù)存在三種運行方式,并非一定需要打開配置文件
*/
#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 的參數(shù)進行設置,為了方便閱讀省略此處代碼
      */

      ...
     /*
        將函數(shù)的運行模式定位為 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 下面給出來返回參數(shù)的詳細英文注釋     */
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*/
     /*
      如果錯誤,調(diào)轉(zhuǎn)到done處執(zhí)行
      */
if (rc == NGX_ERROR) {goto done;}
      /*
        如果如到“}”符號,跳轉(zhuǎn)到done處執(zhí)行,出現(xiàn)錯誤跳到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;}
    /*
      如果配置文件全部解析完成,調(diào)轉(zhuǎn)到done處執(zhí)行。
    */
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;}
      /*
        如果遇到“{"但出現(xiàn)錯誤,調(diào)轉(zhuǎn)到failed 處執(zhí)行
      */
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;}}/*
      前面對可能出現(xiàn)的情況都進行了相應的跳轉(zhuǎn),那么剩下的就是讀取 指令正確后執(zhí)行的過程了,主要分為兩種,一種為NGX_OK 一般指令的進行如:worker_processes
      另一種 NGX_CONF_BLOCK_START 就是以{作為結束符指令的執(zhí)行,如:events、http 這類有二級指令的。
      rc == NGX_OK || rc == NGX_CONF_BLOCK_START
       */
if (cf->handler) {/*
        指令執(zhí)行前是否要進行些處理工作
* 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;}/*
      下一個關鍵函數(shù) 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; }

  在以上代碼中,除了將關鍵函數(shù)用紅色標記以外,還特意將 函數(shù)中 對上下文的保存和還原 工作的地方進行了紅色標記,因為在nginx源碼中經(jīng)常使用到這種機制,可以記住下這樣的寫法。

  4、函數(shù)ngx_conf_handler?指令處理函數(shù),關鍵函數(shù)!

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++) { /*
          遍歷指令集中的指令,并找尋 從配置文件中讀取到的 指令相對應的 內(nèi)容
        */
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;}
        ...

      /*判斷指令參數(shù)是否正確*/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) {
         }
          ...
}/*

        通過指令的類型,來設置執(zhí)行指令時需要的 模塊前期創(chuàng)建的 cf_ctx里面的配置信息,朔源就是 cycle->conf_ctx 當然它指向的 上下文 可能已經(jīng)發(fā)生了改變         */
        conf
= NULL;
        
if (cmd->type & NGX_DIRECT_CONF) { conf = ((void **) cf->ctx)[ngx_modules[i]->index]; }
          ...
/*
        執(zhí)行指令對應的 功能函數(shù)!!
        */rv
= cmd->set(cf, cmd, conf);

        /*

          如果執(zhí)行成功,返回 成功。

        */

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

        /*
          至此,配置文件的指令執(zhí)行就結束了。后面都是一些出錯處理,在此省略。
        */ ...
}} ... }

  寫到這里時間已經(jīng)有些晚了,小結一下。通過代碼摘錄的介紹,將整個nginx.conf解析的流程 概括的演示了出來,對于其中的些地方可能還不明晰如:二級模塊的指令是如何執(zhí)行的(就是 events{ ... }、http{ ... } 括號里面的指令如何執(zhí)行的)、非核心模塊是如何加入對 nginx.conf 這個配置文件進行解析 等一些內(nèi)容,在后面的分析中再寫吧。晚安!?

轉(zhuǎn)載于:https://www.cnblogs.com/jzhlin/archive/2012/06/18/nginx_conf_1.html

總結

以上是生活随笔為你收集整理的Nginx 源码分析-- 模块module 解析执行 nginx.conf 配置文件流程分析 一的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。