nginx 源碼學習筆記——文件讀寫和配置文件讀取

對於c語言來說,如果需要支持多個操作系統,就需要封裝一下文件的讀寫。封裝文件的讀寫還有一個益處就是能夠把讀寫異常,讀寫的內存控制,日誌的記錄封裝起來,以便於其他的模塊更好的應用。文件的讀寫一般會封裝成打開文件,關閉打開的文件,讀寫文件。

在nginx的源碼中,文件讀寫主要放在core/ngx_file.c,core/ngx_file.h,src/os/unix/ngx_files.h和src/os/unix/ngx_files.c中。由於nginx的文件讀寫函數較多,我們只是詳細介紹比較重要,經常使用,實現很有技巧的函數。

  1. typedef struct {  
  2.     ngx_str_t                  name;             //路徑數據字符串  
  3.     size_t                     len;              //目錄長度  
  4.     size_t                     level[3];         //臨時目錄的三級目錄大小  
  5.   
  6.     ngx_path_manager_pt        manager;  
  7.     ngx_path_loader_pt         loader;  
  8.     void                      *data;              
  9.   
  10.     u_char                    *conf_file;        //該路徑的來源的配置文件  
  11.     ngx_uint_t                 line;             //該路徑在來源的配置文件中的行數,主要用於記錄日誌,排查錯誤  
  12. } ngx_path_t;  


我們首先介紹簡單封裝的函數,再介紹複雜封裝的函數,簡單封裝的函數有如下函數:
ngx_open_file/ngx_close_file

  1. src/os/unix/ngx_files.h  
  2. #define ngx_open_file(name, mode, create, access)                            \  
  3.     open((const char *) name, mode|create|O_BINARY, access)  
  4.   
  5. #else  
  6.   
  7. #define ngx_open_file(name, mode, create, access)                            \  
  8.     open((const char *) name, mode|create, access)  
  9.   
  10. #endif  
  11.   
  12. #define ngx_close_file           close  


這裏可以看到單純的對c語言的open和close進行了封裝,是不是非常簡單呢?

  1. src/os/unix/ngx_files.h  
  2. #define ngx_delete_file(name)    unlink((const char *) name)  


ngx_delete_file刪除文件函數,調用系統的unlink函數,unlink()會刪除pathname指定的文件。如果該文件名最後連接點,但有其他進程打開了此文件,則在所有關於此文件的文件描述詞皆關閉後纔會刪除。如果參數pathname爲一符號連接(symboliclink),則此連接會被刪除。

在ngx_files.c文件中存在大量的文件讀寫操作,這裏就不一一講解;

配置文件一般有三個作用:

根據配置文件啓用某段程序,

用配置文件傳入參數,

設定啓動程序程序之間的相互關係。

Nginx的配置文件也實現了這三部分的功能,nginx的配置文件主要有以下幾個主要的結構體和函數配置文件的結構體有:

結構體說明
ngx_command_s           定義了配置文件中的 tag的配置,以及遇到該tag該怎麼處理的函數
ngx_open_file_s            定義了打開文件的參數的結構體
ngx_conf_file_t             定義了緩存配置文件的數據的結構體
ngx_conf_s                    定義了配置文件解析過程中需要緩存的數據

ngx_command_s          這個結構體定義了配置文件中的tag,以及遇到該tag,該怎麼處理,其結構如下表:

結構體說明
name 配置文件中的
tag
Type                    
配置類型,這個參數中會定義這個配置是什麼範圍內的配置(核心配置或是普通配置),以及有多少參數, 是塊配置,還是行配置
Set                       解析該配置的函數
ConfOffset           指定配置存儲的位置
Post                     指向模塊在讀配置的時候需要的一些零碎變量。一般它是NULL

在每一個ngx_command_s數組的結尾必須有一個ngx_null_command,以用於判斷是否結束。
配置文件解析的入口爲ngx_conf_parse,如果瞭解了ngx_conf_parse,對nginx的配置文件的原理就有了基本的瞭解,下面我們詳細的解釋一下

  1. src/ngx_conf_file.h  
  2.   
  3. char *  
  4. ngx_conf_parse(ngx_conf_t *cf, ngx_str_t *filename)   
  5. //cf是輸入參數也是輸出參數,在文件名爲空的情況下,第二個  
  6. //參數是文件名,可能爲空,一般在解析配置塊或是一行的時候。  
  7. {  
  8.     char             *rv;  
  9.     ngx_fd_t          fd;  
  10.     ngx_int_t         rc;  
  11.     ngx_buf_t         buf;  
  12.     ngx_conf_file_t  *prev, conf_file;  
  13.     enum {  
  14.         parse_file = 0,  
  15.         parse_block,  
  16.         parse_param  
  17.     } type;  
  18.   
  19. #if (NGX_SUPPRESS_WARN)  
  20.     fd = NGX_INVALID_FILE;  
  21.     prev = NULL;  
  22. #endif  
  23.   
  24.     if (filename) { //如果文件名不爲空 則打開配置文件  
  25.   
  26.         /* open configuration file */  
  27.   
  28.         fd = ngx_open_file(filename->data, NGX_FILE_RDONLY, NGX_FILE_OPEN, 0);<span style="color:#ff0000;">//打開配置文件</span>  
  29.         if (fd == NGX_INVALID_FILE) {  
  30.             ngx_conf_log_error(NGX_LOG_EMERG, cf, ngx_errno,  
  31.                                ngx_open_file_n " \"%s\" failed",  
  32.                                filename->data);  
  33.             return NGX_CONF_ERROR;  
  34.         }  
  35.   
  36.         prev = cf->conf_file;  
  37.   
  38.         cf->conf_file = &conf_file;  
  39.   
  40.         if (ngx_fd_info(fd, &cf->conf_file->file.info) == -1) {  
  41.             ngx_log_error(NGX_LOG_EMERG, cf->log, ngx_errno,  
  42.                           ngx_fd_info_n " \"%s\" failed", filename->data);  
  43.         }  
  44.   
  45.         cf->conf_file->buffer = &buf;  
  46.   
  47.         buf.start = ngx_alloc(NGX_CONF_BUFFER, cf->log);  
  48.         if (buf.start == NULL) {  
  49.             goto failed;  
  50.         }  
  51.   
  52.         buf.pos = buf.start;  
  53.         buf.last = buf.start;  
  54.         buf.end = buf.last + NGX_CONF_BUFFER;  
  55.         buf.temporary = 1;  
  56.   
  57.         cf->conf_file->file.fd = fd;  
  58.         cf->conf_file->file.name.len = filename->len;  
  59.         cf->conf_file->file.name.data = filename->data;  
  60.         cf->conf_file->file.offset = 0;  
  61.         cf->conf_file->file.log = cf->log;  
  62.         cf->conf_file->line = 1;  
  63.   
  64.         type = parse_file;  
  65.   
  66.     } else if (cf->conf_file->file.fd != NGX_INVALID_FILE) {  
  67.   
  68.         type = parse_block;  
  69.   
  70.     } else {  
  71.         type = parse_param;  
  72.     }  
  73.   
  74.   
  75.     for ( ;; ) {  
  76.         rc = ngx_conf_read_token(cf);      
  77.        //ngx_conf_read_token函數的主要功能是讀取並解析配置文件,  
  78.         //解析的參數存到cf->args中,讀取到";"標點則返回  
  79.         //讀取到"{",則接着讀取,讀取到"}",這直接完成。  
  80.   
  81.         /* 
  82.          * ngx_conf_read_token() may return 
  83.          * 
  84.          *    NGX_ERROR             there is error 
  85.          *    NGX_OK                the token terminated by ";" was found 
  86.          *    NGX_CONF_BLOCK_START  the token terminated by "{" was found 
  87.          *    NGX_CONF_BLOCK_DONE   the "}" was found 
  88.          *    NGX_CONF_FILE_DONE    the configuration file is done 
  89.          */  
  90.   
  91.         if (rc == NGX_ERROR) {  
  92.             goto done;                    //如果錯誤 結束  
  93.         }  
  94.   
  95.         if (rc == NGX_CONF_BLOCK_DONE) {   //如果發現“}”  
  96.   
  97.             if (type != parse_block) {  
  98.                 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "unexpected \"}\"");  
  99.                 goto failed;  
  100.             }  
  101.   
  102.             goto done;  
  103.         }  
  104.   
  105.         if (rc == NGX_CONF_FILE_DONE) {     //如果發現文件結束  
  106.   
  107.             if (type == parse_block) {  
  108.                 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,  
  109.                                    "unexpected end of file, expecting \"}\"");  
  110.                 goto failed;  
  111.             }  
  112.   
  113.             goto done;  
  114.         }  
  115.   
  116.         if (rc == NGX_CONF_BLOCK_START) {   //如果發現“{”  
  117.   
  118.             if (type == parse_param) {  
  119.                 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,  
  120.                                    "block directives are not supported "  
  121.                                    "in -g option");  
  122.                 goto failed;  
  123.             }  
  124.         }  
  125.   
  126.         /* rc == NGX_OK || rc == NGX_CONF_BLOCK_START */  
  127.   
  128.         if (cf->handler) {  //這個函數只在模塊的時候使用type  
  129.   
  130.             /* 
  131.              * the custom handler, i.e., that is used in the http's 
  132.              * "types { ... }" directive 
  133.              */  
  134.   
  135.             rv = (*cf->handler)(cf, NULL, cf->handler_conf);   
  136.             if (rv == NGX_CONF_OK) {  
  137.                 continue;  
  138.             }  
  139.   
  140.             if (rv == NGX_CONF_ERROR) {  
  141.                 goto failed;  
  142.             }  
  143.   
  144.             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, rv);  
  145.   
  146.             goto failed;  
  147.         }  
  148.   
  149.   
  150.         rc = ngx_conf_handler(cf, rc);  
  151.         //ngx_conf_handler函數主要功能是先驗證配置有沒有問題,然後調用cmd->set函數  
  152.         if (rc == NGX_ERROR) {  
  153.             goto failed;  
  154.         }  
  155.     }  
  156.   
  157. failed:  
  158.   
  159.     rc = NGX_ERROR;  
  160.   
  161. done:  
  162.   
  163.     if (filename) {  
  164.         if (cf->conf_file->buffer->start) {  
  165.             ngx_free(cf->conf_file->buffer->start);  
  166.         }  
  167.   
  168.         if (ngx_close_file(fd) == NGX_FILE_ERROR) { //關閉文件  
  169.             ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno,  
  170.                           ngx_close_file_n " %s failed",  
  171.                           filename->data);  
  172.             return NGX_CONF_ERROR;  
  173.         }  
  174.   
  175.         cf->conf_file = prev;  
  176.     }  
  177.   
  178.     if (rc == NGX_ERROR) {  
  179.         return NGX_CONF_ERROR;  
  180.     }  
  181.   
  182.     return NGX_CONF_OK;  
  183. }  



ngx_conf_parse函數除了在ngx_init_cycle函數中調用外,在配置塊的解析中,即cmd->set函數(例如解析http配置塊的ngx_http_block函數)中也會調用該函數,從某種程度上理解該函數其實是一個遞歸函數,只不過中間調用了其他函數。在講解http的配置文件那一章我們會根據http的配置例子詳細的講解。


本文轉載自 :http://www.cnblogs.com/h2-database/archive/2012/05/16/2583269.html

發佈了14 篇原創文章 · 獲贊 4 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章