對於c語言來說,如果需要支持多個操作系統,就需要封裝一下文件的讀寫。封裝文件的讀寫還有一個益處就是能夠把讀寫異常,讀寫的內存控制,日誌的記錄封裝起來,以便於其他的模塊更好的應用。文件的讀寫一般會封裝成打開文件,關閉打開的文件,讀寫文件。
在nginx的源碼中,文件讀寫主要放在core/ngx_file.c,core/ngx_file.h,src/os/unix/ngx_files.h和src/os/unix/ngx_files.c中。由於nginx的文件讀寫函數較多,我們只是詳細介紹比較重要,經常使用,實現很有技巧的函數。
- typedef struct {
- ngx_str_t name; //路徑數據字符串
- size_t len; //目錄長度
- size_t level[3]; //臨時目錄的三級目錄大小
- ngx_path_manager_pt manager;
- ngx_path_loader_pt loader;
- void *data;
- u_char *conf_file; //該路徑的來源的配置文件
- ngx_uint_t line; //該路徑在來源的配置文件中的行數,主要用於記錄日誌,排查錯誤
- } ngx_path_t;
我們首先介紹簡單封裝的函數,再介紹複雜封裝的函數,簡單封裝的函數有如下函數:
ngx_open_file/ngx_close_file
- src/os/unix/ngx_files.h
- #define ngx_open_file(name, mode, create, access) \
- open((const char *) name, mode|create|O_BINARY, access)
- #else
- #define ngx_open_file(name, mode, create, access) \
- open((const char *) name, mode|create, access)
- #endif
- #define ngx_close_file close
這裏可以看到單純的對c語言的open和close進行了封裝,是不是非常簡單呢?
- src/os/unix/ngx_files.h
- #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的配置文件的原理就有了基本的瞭解,下面我們詳細的解釋一下
- src/ngx_conf_file.h
- char *
- ngx_conf_parse(ngx_conf_t *cf, ngx_str_t *filename)
- //cf是輸入參數也是輸出參數,在文件名爲空的情況下,第二個
- //參數是文件名,可能爲空,一般在解析配置塊或是一行的時候。
- {
- 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
- if (filename) { //如果文件名不爲空 則打開配置文件
- /* open configuration file */
- fd = ngx_open_file(filename->data, NGX_FILE_RDONLY, NGX_FILE_OPEN, 0);<span style="color:#ff0000;">//打開配置文件</span>
- if (fd == NGX_INVALID_FILE) {
- ngx_conf_log_error(NGX_LOG_EMERG, cf, ngx_errno,
- ngx_open_file_n " \"%s\" failed",
- filename->data);
- return NGX_CONF_ERROR;
- }
- prev = cf->conf_file;
- cf->conf_file = &conf_file;
- if (ngx_fd_info(fd, &cf->conf_file->file.info) == -1) {
- ngx_log_error(NGX_LOG_EMERG, cf->log, ngx_errno,
- ngx_fd_info_n " \"%s\" failed", filename->data);
- }
- cf->conf_file->buffer = &buf;
- buf.start = ngx_alloc(NGX_CONF_BUFFER, cf->log);
- if (buf.start == NULL) {
- goto failed;
- }
- buf.pos = buf.start;
- buf.last = buf.start;
- buf.end = buf.last + NGX_CONF_BUFFER;
- buf.temporary = 1;
- cf->conf_file->file.fd = fd;
- cf->conf_file->file.name.len = filename->len;
- cf->conf_file->file.name.data = filename->data;
- cf->conf_file->file.offset = 0;
- cf->conf_file->file.log = cf->log;
- cf->conf_file->line = 1;
- type = parse_file;
- } else if (cf->conf_file->file.fd != NGX_INVALID_FILE) {
- type = parse_block;
- } else {
- type = parse_param;
- }
- for ( ;; ) {
- rc = ngx_conf_read_token(cf);
- //ngx_conf_read_token函數的主要功能是讀取並解析配置文件,
- //解析的參數存到cf->args中,讀取到";"標點則返回
- //讀取到"{",則接着讀取,讀取到"}",這直接完成。
- /*
- * 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
- */
- if (rc == NGX_ERROR) {
- goto done; //如果錯誤 結束
- }
- if (rc == NGX_CONF_BLOCK_DONE) { //如果發現“}”
- if (type != parse_block) {
- ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "unexpected \"}\"");
- goto failed;
- }
- goto 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;
- }
- 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;
- }
- }
- /* rc == NGX_OK || rc == NGX_CONF_BLOCK_START */
- if (cf->handler) { //這個函數只在模塊的時候使用type
- /*
- * 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;
- }
- rc = ngx_conf_handler(cf, rc);
- //ngx_conf_handler函數主要功能是先驗證配置有沒有問題,然後調用cmd->set函數
- if (rc == NGX_ERROR) {
- goto failed;
- }
- }
- failed:
- rc = NGX_ERROR;
- done:
- if (filename) {
- if (cf->conf_file->buffer->start) {
- ngx_free(cf->conf_file->buffer->start);
- }
- if (ngx_close_file(fd) == NGX_FILE_ERROR) { //關閉文件
- ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno,
- ngx_close_file_n " %s failed",
- filename->data);
- return NGX_CONF_ERROR;
- }
- cf->conf_file = prev;
- }
- if (rc == NGX_ERROR) {
- return NGX_CONF_ERROR;
- }
- return NGX_CONF_OK;
- }
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