網(wǎng)上有很多關(guān)于pos機初始化通訊失敗,Nginx源碼分析之模塊初始化的知識,也有很多人為大家解答關(guān)于pos機初始化通訊失敗的問題,今天pos機之家(www.afbey.com)為大家整理了關(guān)于這方面的知識,讓我們一起來看下吧!
本文目錄一覽:
pos機初始化通訊失敗
在Nginx啟動過程中,模塊的初始化是整個啟動過程中的重要部分,而且了解了模塊初始化的過程對應(yīng)后面具體分析各個模塊會有事半功倍的效果。在我看來,分析源碼來了解模塊的初始化是最直接不過的了,所以下面主要通過結(jié)合源碼來分析模塊的初始化過程。
稍微了解nginx的人都知道nginx是高度模塊化的,各個功能都封裝在模塊中,而各個模塊的初始化則是根據(jù)配置文件來進行的,下面我們會看到nginx邊解析配置文件中的指令,邊初始化指令所屬的模塊,指令其實就是指示怎樣初始化模塊的。
模塊初始化框架模塊的初始化主要在函數(shù)ngx_init_cycle(src/ngx_cycle.c)中下列代碼完成:
ngx_cycle_t * 2 ngx_init_cycle(ngx_cycle_t *old_cycle) 3 { 4 ... 5 //配置上下文 6 cycle->conf_ctx = ngx_pcalloc(pool, ngx_max_module * sizeof(void *)); 7 ... 8 //處理core模塊,cycle->conf_ctx用于存放所有CORE模塊的配置 9 for (i = 0; ngx_modules[i]; i++) {10 if (ngx_modules[i]->type != NGX_CORE_MODULE) { //跳過不是nginx的內(nèi)核模塊11 continue;12 }13 module = ngx_modules[i]->ctx;14 //只有ngx_core_module有create_conf回調(diào)函數(shù),這個會調(diào)用函數(shù)會創(chuàng)建ngx_core_conf_t結(jié)構(gòu),15 //用于存儲整個配置文件main scope范圍內(nèi)的信息,比如worker_processes,worker_cpu_affinity等16 if (module->create_conf) {17 rv = module->create_conf(cycle);18 ...19 cycle->conf_ctx[ngx_modules[i]->index] = rv;20 }21 }22 //conf表示當前解析到的配置命令上下文,包括命令,命令參數(shù)等23 conf.args = ngx_array_create(pool, 10, sizeof(ngx_str_t));24 ...25 conf.temp_pool = ngx_create_pool(NGX_CYCLE_POOL_SIZE, log);26 ...27 conf.ctx = cycle->conf_ctx;28 conf.cycle = cycle;29 conf.pool = pool;30 conf.log = log;31 conf.module_type = NGX_CORE_MODULE; //conf.module_type指示將要解析這個類型模塊的指令32 conf.cmd_type = NGX_MAIN_CONF; //conf.cmd_type指示將要解析的指令的類型33 //真正開始解析配置文件中的每個命令34 if (ngx_conf_parse(&conf, &cycle->conf_file) != NGX_CONF_OK) {35 ...36 }37 ...38 //初始化所有core module模塊的config結(jié)構(gòu)。調(diào)用ngx_core_module_t的init_conf,39 //在所有core module中,只有ngx_core_module有init_conf回調(diào),40 //用于對ngx_core_conf_t中沒有配置的字段設(shè)置默認值41 for (i = 0; ngx_modules[i]; i++) {42 if (ngx_modules[i]->type != NGX_CORE_MODULE) {43 continue;44 }45 module = ngx_modules[i]->ctx;46 if (module->init_conf) {47 if (module->init_conf(cycle, cycle->conf_ctx[ngx_modules[i]->index])48 == NGX_CONF_ERROR)49 {50 environ = senv;51 ngx_destroy_cycle_pools(&conf);52 return NULL;53 }54 }55 }56 ...57 }
cycle->conf_ctx是一個指針數(shù)組,數(shù)組中的每個元素對應(yīng)某個模塊的配置信息。ngx_conf_parse用戶真正解析配置文件中的命令,conf存放解析配置文件的上下文信息,如module_type表示將要解析模塊的類型,cmd_type表示將要解析的指令的類型,ctx指向解析出來信息的存放地址,args存放解析到的指令和參數(shù)。具體每個模塊配信息的存放如下圖所示,NGX_MAIN_CONF表示的是全局作用域?qū)?yīng)的配置信息,NGX_EVENT_CONF表示的是EVENT模塊對應(yīng)的配置信息,NGX_HTTP_MAIN_CONF,NGX_HTTP_SRV_CONF,NGX_HTTP_LOC_CONF表示的是HTTP模塊對應(yīng)的main,server,local域的配置信息。
下面我們來具體看下ngx_conf_parse函數(shù)是怎樣解析每個指令的。
char * 2 ngx_conf_parse(ngx_conf_t *cf, ngx_str_t *filename) 3 { 4 ... 5 if (filename) { 6 //打開配置文件 7 fd = ngx_open_file(filename->data, NGX_FILE_RDONLY, NGX_FILE_OPEN, 0); 8 ... 9 prev = cf->conf_file;10 cf->conf_file = &conf_file;11 //獲取配置文件信息12 if (ngx_fd_info(fd, &cf->conf_file->file.info) == NGX_FILE_ERROR) {13 ...14 }15 //配置緩沖區(qū)用于存放配置文件信息16 cf->conf_file->buffer = &buf;17 //NGX_CONF_BUFFER = 4096,直接malloc18 buf.start = ngx_alloc(NGX_CONF_BUFFER, cf->log);19 ...20 //[pos,last)表示緩存中真正存儲了數(shù)據(jù)的區(qū)間,[start,end)表示緩存區(qū)的物理區(qū)域21 buf.pos = buf.start;22 buf.last = buf.start;23 buf.end = buf.last + NGX_CONF_BUFFER;24 buf.temporary = 1;25 cf->conf_file->file.fd = fd;26 cf->conf_file->file.name.len = filename->len;27 cf->conf_file->file.name.data = filename->data;28 cf->conf_file->file.offset = 0;29 cf->conf_file->file.log = cf->log;30 cf->conf_file->line = 1;31 type = parse_file;32 33 } 34 ...35 for ( ;; ) {36 rc = ngx_conf_read_token(cf); //從配置文件中讀取下一個命令37 ...38 rc = ngx_conf_handler(cf, rc); //查找命令所在的模塊,執(zhí)行命令對應(yīng)的函數(shù)39 ...40 }41 ...42 }
ngx_conf_parse是配置解析的入口函數(shù),它根據(jù)當成上下文讀取配置文件數(shù)據(jù),進行分析的同時對配置文件語法進行檢查。同時,如果遇到的指令包含塊,這個函數(shù)會在指令處理函數(shù)修改作用域等上下文信息后,被間接遞歸調(diào)用來處理塊中的配置信息。第一次調(diào)用ngx_conf_parse時,函數(shù)會打開配置文件,設(shè)置正在執(zhí)行的解析類型,讀取命令,然后調(diào)用ngx_conf_handler。我們先來看下ngx_conf_read_token怎么讀取命令的:
//解析一個命令和其所帶的參數(shù) 2 static ngx_int_t 3 ngx_conf_read_token(ngx_conf_t *cf) 4 { 5 ... 6 found = 0; //標記是否找到一個命令 7 need_space = 0; //下一個字符希望是空格 8 last_space = 1; //上一個字符是空格 9 sharp_comment = 0; //注釋10 variable = 0; //存在變量11 quoted = 0; //\\符號12 s_quoted = 0; //單引號13 d_quoted = 0; //雙引號14 ...15 for ( ;; ) {16 ch = *b->pos++; //當前字符存儲于ch中17 if (ch == LF) { //換行18 if (sharp_comment) { //注釋結(jié)束,只有行注釋19 sharp_comment = 0;20 }21 }22 if (sharp_comment) { //跳過注釋,直到換行23 continue;24 }25 if (quoted) { //如果上一個字符是\\,則跳過當前字符,后面讀取token會做處理26 quoted = 0;27 continue;28 }29 if (need_space) { //次字符必須是space分割符30 /*31 忽略掉space字符;space字符包括' ','\',CR,LF32 如果字符是';','{',此次命令讀取結(jié)束;33 如果字符是')',開始讀取新的token;34 如果讀到其它字符則解析失敗35 */36 }37 if (last_space) { //表示一個token開始了,第一個非space字符38 /*39 忽略掉space字符;40 如果字符是';','{','}',此次命令讀取結(jié)束;41 如果字符是'#',字符后面是注釋;42 如果字符是'\\',下一個字符將被忽略43 如果字符是'"',''',下一個字符在單引號或雙引號中44 */45 } else { //開始讀取新token46 /*47 如果字符是'$',后面的非space字符組成變量token;48 碰到了結(jié)束引號'"','''時,token讀取完成;49 碰到了space字符,token讀取完成50 */51 if (found){52 /*53 將找到的token追加到cf->args數(shù)組中,并且每個token字符串以'\\0'結(jié)束54 */55 }56 }57 }58 }
下面我們再來看下命令處理函數(shù)ngx_conf_handler:
static ngx_int_t 2 ngx_conf_handler(ngx_conf_t *cf, ngx_int_t last) 3 { 4 ... 5 for (i = 0; ngx_modules[i]; i++) { 6 cmd = ngx_modules[i]->commands; 7 ... 8 for ( /* void */ ; cmd->name.len; cmd++) { 9 //命令名稱對比10 //模塊類型對比11 //命令類型對比12 //命令是否帶塊13 //檢測命令參數(shù)14 conf = NULL;15 if (cmd->type & NGX_DIRECT_CONF) {16 conf = ((void **) cf->ctx)[ngx_modules[i]->index];17 18 } else if (cmd->type & NGX_MAIN_CONF) {19 conf = &(((void **) cf->ctx)[ngx_modules[i]->index]);20 21 } else if (cf->ctx) {22 confp = *(void **) ((char *) cf->ctx + cmd->conf);23 24 if (confp) {25 conf = confp[ngx_modules[i]->ctx_index];26 }27 }28 //調(diào)用命令中的set函數(shù)29 rv = cmd->set(cf, cmd, conf);30 ...31 }32 }33 ...34 }
完全讀取到一條配置指令后,Nginx會使用該指令名在所有指令定義中進行查找。但是,在進行查找之前,Nginx會先驗證模塊的類型和當前解析函數(shù)上下文中的類型是否一致。隨后,在某個模塊中找到匹配的指令定義后,還會驗證指令可以出現(xiàn)的作用域是否包含當前解析函數(shù)上下文中記錄的作用域。最后,檢查指令的參數(shù)個數(shù)是否和指令定義中標明的一致。
校驗工作完成后,Nginx將指令名和所有模塊預(yù)定義支持的指令進行對比,找到完全匹配的配置指令定義。根據(jù)配置指令的不同類型,配置項的存儲位置也不同。
NGX_DIRECT_CONF類型的配置指令,其配置項存儲空間是全局作用域?qū)?yīng)的存儲空間。這個類型的指令主要出現(xiàn)在ngx_core_module模塊里。
1 conf = ((void **) cf->ctx)[ngx_modules[i]->index];
NGX_MAIN_CONF表示配置指令的作用域為全局作用域??v觀Nginx整個代碼,除了ngx_core_module的配置指令(同時標識為NGX_DIRECT_CONF)位于這個作用域中外,另外幾個定義新的子級作用域的指令–events、http、mail、imap,都是非NGX_DIRECT_CONF的NGX_MAIN_CONF指令,它們在全局作用域中并未被分配空間,所以在指令處理函數(shù)中分配的空間需要掛接到全局作用域中,故傳遞給指令處理函數(shù)的參數(shù)是全局作用域的地址。
1 conf = &(((void **) cf->ctx)[ngx_modules[i]->index];
其它類型配置指令項的存儲位置和指令出現(xiàn)的作用域(并且非全局作用域)有關(guān):
1 confp = *(void **) ((char *) cf->ctx + cmd->conf); 2 if (confp) { conf = confp[ngx_modules[i]->ctx_index]; }
配置項將要存儲的位置確定后,調(diào)用指令處理函數(shù),完成配置項初始化和其它工作。
rc = cmd->set(cf, cmd, conf);
下面通過分析模塊HTTP的初始化來進一步加深理解模塊的初始化。
相關(guān)視頻推薦16萬Nginx源碼就該這樣讀
如何拿到40k的offer, nginx模塊開發(fā)可以幫你完成
手把手帶你實現(xiàn)一個nginx模塊
C/C++Linux服務(wù)器開發(fā)/后臺架構(gòu)師【零聲教育】-學習視頻教程-騰訊課堂
【文章福利】:小編整理了一些個人覺得比較好的學習書籍、視頻資料共享在群文件里面,有需要的可以自行添加哦!~點擊加入(832218493需要自?。?/strong>
HTTP模塊的初始化http模塊由很多個模塊組成,這里主要講解兩個主要模塊的初始化,它們是ngx_http_module和ngx_http_core_module。ngx_http_moduel模塊很簡單,它的定義如下:
static ngx_command_t ngx_http_commands[] = { 2 { ngx_string("http"), //http命令描述結(jié)構(gòu) 3 NGX_MAIN_CONF|NGX_CONF_BLOCK|NGX_CONF_NOARGS, 4 ngx_http_block, 5 0, 6 0, 7 NULL }, 8 ngx_null_command 9 };10 static ngx_core_module_t ngx_http_module_ctx = {11 ngx_string("http"),12 NULL,13 NULL14 };15 ngx_module_t ngx_http_module = {16 NGX_MODULE_V1,17 &ngx_http_module_ctx, /* module context */18 ngx_http_commands, /* module directives */19 NGX_CORE_MODULE, /* module type */20 ...21 };
從模塊的定義看,它是一個NGX_CORE_MODULE類型的模塊,就包含一條指令http,當在全局作用域中遇到http指令后,會調(diào)用ngx_http_block函數(shù),傳遞給該函數(shù)的參數(shù)為:cf,當前配置上下文信息;cmd,http命令描述結(jié)構(gòu);conf,ngx_http_module模塊在全局作用域數(shù)組中的地址。下面看下ngx_http_block函數(shù):
static char * 2 ngx_http_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) 3 { 4 ... 5 ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_conf_ctx_t)); //http main配置結(jié)構(gòu) 6 ... 7 *(ngx_http_conf_ctx_t **) conf = ctx; //將http main配置結(jié)構(gòu)掛到全局作用域上 8 //計算NGX_HTTP_MODULE類型模塊的個數(shù),并計算每個NGX_HTTP_MODULE模塊在全部NGX_HTTP_MODULE模塊中的下標 9 ngx_http_max_module = 0;10 for (m = 0; ngx_modules[m]; m++) {11 if (ngx_modules[m]->type != NGX_HTTP_MODULE) {12 continue;13 }14 ngx_modules[m]->ctx_index = ngx_http_max_module++;15 }16 //http的main域配置17 ctx->main_conf = ngx_pcalloc(cf->pool,18 sizeof(void *) * ngx_http_max_module);19 ...20 //http的server域,用來合并server塊中的域21 ctx->srv_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_http_max_module);22 ...23 //http的local域,用來合并server塊中的local塊中的域24 ctx->loc_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_http_max_module);25 //創(chuàng)建各個作用域?qū)?yīng)的配置結(jié)構(gòu)26 for (m = 0; ngx_modules[m]; m++) {27 if (ngx_modules[m]->type != NGX_HTTP_MODULE) {28 continue;29 }30 module = ngx_modules[m]->ctx;31 mi = ngx_modules[m]->ctx_index;32 if (module->create_main_conf) {33 ctx->main_conf[mi] = module->create_main_conf(cf);34 ...35 }36 if (module->create_srv_conf) {37 ctx->srv_conf[mi] = module->create_srv_conf(cf);38 ...39 }40 if (module->create_loc_conf) {41 ctx->loc_conf[mi] = module->create_loc_conf(cf);42 ...43 }44 }45 pcf = *cf;46 cf->ctx = ctx; //更新配置上下文為http的上下文47 ...48 //遞歸ngx_conf_parse來調(diào)用處理http包含的塊的配置信息49 cf->module_type = NGX_HTTP_MODULE; //模塊類型為NGX_HTTP_MODULE50 cf->cmd_type = NGX_HTTP_MAIN_CONF; //指令的作用域51 rv = ngx_conf_parse(cf, NULL);52 ...53 *cf = pcf; //恢復(fù)配置上下文54 ...55 }
到這里,已經(jīng)創(chuàng)建的配置信息如下圖所示:
遞歸調(diào)用ngx_conf_parse后,接下來處理的每個指令都是NGX_HTTP_MAIN_CONF作用域的,每個指令的處理函數(shù)會初始化應(yīng)配置結(jié)構(gòu)信息,而具體的配置信息存放在哪個數(shù)組里面由指令定義中的conf字段決定,即一定是main_conf,srv_conf和loc_conf之中的一種。NGX_HTTP_MAIN_CONF作用域中的很多指令都屬于ngx_http_core_module模塊,下面看下這個模塊的定義:
static ngx_command_t ngx_http_core_commands[] = { 2 ... 3 { ngx_string("server"), //server指令 4 NGX_HTTP_MAIN_CONF|NGX_CONF_BLOCK|NGX_CONF_NOARGS, 5 ngx_http_core_server, 6 0, 7 0, 8 NULL }, 9 { ngx_string("location"), //location指令10 NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_BLOCK|NGX_CONF_TAKE12,11 ngx_http_core_location,12 NGX_HTTP_SRV_CONF_OFFSET,13 0,14 NULL },15 ...16 }17 18 static ngx_http_module_t ngx_http_core_module_ctx = {19 ngx_http_core_preconfiguration, /* preconfiguration */20 NULL, /* postconfiguration */21 ngx_http_core_create_main_conf, /* create main configuration */22 ngx_http_core_init_main_conf, /* init main configuration */23 ngx_http_core_create_srv_conf, /* create server configuration */24 ngx_http_core_merge_srv_conf, /* merge server configuration */25 ngx_http_core_create_loc_conf, /* create location configuration */26 ngx_http_core_merge_loc_conf /* merge location configuration */27 };28 ngx_module_t ngx_http_core_module = {29 NGX_MODULE_V1,30 &ngx_http_core_module_ctx, /* module context */31 ngx_http_core_commands, /* module directives */32 NGX_HTTP_MODULE, /* module type */33 ...34 };
這個模塊定義了很多指令,其中server和location是比較關(guān)鍵的兩條指令,它們分別處理server和location指令后面所帶有的塊。處理這些塊的方法和處理http指令后面的塊的方法類似,都是修改配置上下文,調(diào)用ngx_conf_parse來處理,當然在處理server塊時只會生成srv_conf和loc_conf數(shù)組,所有的server塊共享一個main_conf數(shù)組,在處理location塊時只會生成loc_conf數(shù)組,同一個server塊中的location共享這個server塊中的ser_conf數(shù)組。
有些指令能同時出現(xiàn)在http塊,server塊和location塊中,并且底層塊中指令會覆蓋上層塊中的定義,如果底層塊中指令沒定義,上層塊的指令定義會傳遞到底層塊中。所以在函數(shù)ngx_http_block調(diào)用ngx_conf_parse解析處理所有的http模塊的配置指令后,調(diào)用ngx_http_merge_servers將http塊中的srv_conf信息傳遞到各個server塊中,在ngx_http_merge_servers中將server塊中的loc_conf信息合并到所有的locations塊中。
以上就是關(guān)于pos機初始化通訊失敗,Nginx源碼分析之模塊初始化的知識,后面我們會繼續(xù)為大家整理關(guān)于pos機初始化通訊失敗的知識,希望能夠幫助到大家!
