pos機(jī)模塊無應(yīng)答,寫一個(gè)Nginx的模塊沒有那么難

 新聞資訊  |   2023-04-16 10:25  |  投稿人:pos機(jī)之家

網(wǎng)上有很多關(guān)于pos機(jī)模塊無應(yīng)答,寫一個(gè)Nginx的模塊沒有那么難的知識(shí),也有很多人為大家解答關(guān)于pos機(jī)模塊無應(yīng)答的問題,今天pos機(jī)之家(m.afbey.com)為大家整理了關(guān)于這方面的知識(shí),讓我們一起來看下吧!

本文目錄一覽:

1、pos機(jī)模塊無應(yīng)答

pos機(jī)模塊無應(yīng)答

Nginx作為世界第二大Web服務(wù)器(第一是Apache),越來越受到大家的青睞。受到歡迎的一個(gè)重要原因,是他的高擴(kuò)展性。它是由多個(gè)不同功能、不同層次、不同類型且耦合度極低的模塊組成。當(dāng)我們開發(fā)自己的模塊時(shí),不僅可以使用core模塊、events模塊、log模塊,而且我們開發(fā)的模塊是嵌入到二進(jìn)制文件中執(zhí)行的,因此我們自己開發(fā)的模塊,也能具有優(yōu)秀的性能,享受Nginx的高并發(fā)特性。

本文以編寫一個(gè)http_hello_module為例,介紹編寫一個(gè)Nginx的http模塊的步驟,以及其中涉及的數(shù)據(jù)結(jié)構(gòu)。以期打破大家對編寫nginx模塊的恐懼。

該示例模塊的功能是:每次訪問http時(shí),http進(jìn)行訪問計(jì)數(shù),并把計(jì)數(shù)的值回顯給客戶端。

為了說明自定義的http模塊,是如何讀取配置文件的值,即在Nginx.conf文件中配置值,我們引入了兩個(gè)配置項(xiàng)hello_string、hello_counter。這兩個(gè)配置指令,僅可以出現(xiàn)在location指令的作用域中。hello_string用于展示字符串類型,它接收一個(gè)參數(shù)來設(shè)置回顯的字符串,或是零個(gè)參數(shù),則使用默認(rèn)的字符串作為回顯的字符串。而hello_counter,用于控制是否開啟訪問統(tǒng)計(jì),如果設(shè)置為 on,則會(huì)在相應(yīng)的字符串后面追加 Visited Times:的字樣,以統(tǒng)計(jì)請求的次數(shù)。我們的例子中,其中一個(gè)location的配置如下。

location /test { hello_string balabala; hello_counter on;}

我們自定義模塊的訪問效果如圖:

編寫http_hello_module

一個(gè)簡單的http模塊,只需要定義一個(gè)結(jié)構(gòu)體ngx_module_t的變量,他告訴Nginx框架,我們定義的模塊,

屬于什么模塊(如http模塊、filter模塊)需要哪些配置項(xiàng),在哪個(gè)領(lǐng)域定義(如server域、http域、location域)。我們的例子中,需要兩個(gè)配置項(xiàng):hello_string,hello_counter。在location作用域配置。配置項(xiàng)的類型,存儲(chǔ)結(jié)構(gòu)。我們的例子中,一個(gè)是string類型,一個(gè)是int類型,定義結(jié)構(gòu)如下:

typedef struct{ ngx_str_t hello_string; ngx_int_t hello_counter;}ngx_http_hello_loc_conf_t;如何接收客戶端請求,對請求,又應(yīng)該做出怎樣的應(yīng)答。

下面,我們逐步了解ngx_module_t結(jié)構(gòu)體是如何完成上述內(nèi)容的。ngx_module_t結(jié)構(gòu)體的每個(gè)成員定義如下:

typedef struct ngx_module_s ngx_module_t;struct ngx_module_s { ngx_uint_t ctx_index; // 表示當(dāng)前模塊在這類模塊中的序號(hào)。既用于表達(dá)優(yōu)先級(jí),又用于 Nginx 框架快速獲得模塊的數(shù)據(jù) ngx_uint_t index; // 當(dāng)前模塊在所有模塊的序號(hào) char *name; ngx_uint_t spare0; // spare系列的保留變量,暫未使用 ngx_uint_t spare1; ngx_uint_t version; // 模塊的版本號(hào),便于將來的擴(kuò)展。 const char *signature; // 用于指向一類模塊的上下文結(jié)構(gòu)體。ctx將會(huì)指向特定類型模塊的公共接口。例如在http模塊中,ctx指向ngx_http_module_t結(jié)構(gòu)體 void *ctx; ngx_command_t *commands; // 將處理nginx.conf中的配置項(xiàng) ngx_uint_t type; // 模塊類型。官方的取值包括:NGX_HTTP_MODULE, NGX_CORE_MODULE, NGX_CONF_MODULE, NGX_EVENT_MODULE, NGX_MAIL_MODULE /* * 以下七個(gè)函數(shù)指針,表示在七個(gè)階段,會(huì)調(diào)用這七個(gè)方法 */ ngx_int_t (*init_master)(ngx_log_t *log); // 在master進(jìn)程啟動(dòng)時(shí)??蚣軙簳r(shí)沒用調(diào)用。所以,寫了也沒啥卵用 ngx_int_t (*init_module)(ngx_cycle_t *cycle); // 在初始化所有模塊時(shí)被調(diào)用。在master/worker模式下,在啟動(dòng)worker進(jìn)程前被調(diào)用 ngx_int_t (*init_process)(ngx_cycle_t *cycle); // 在每個(gè)worker進(jìn)程的初始化過程會(huì)被調(diào)用 ngx_int_t (*init_thread)(ngx_cycle_t *cycle); // 不支持多線程,所以沒啥卵用 void (*exit_thread)(ngx_cycle_t *cycle); // 不支持 void (*exit_process)(ngx_cycle_t *cycle); // worker 進(jìn)程會(huì)在退出前調(diào)用 void (*exit_master)(ngx_cycle_t *cycle); // 在master進(jìn)程退出前被調(diào)用 //沒有用 uintptr_t spare_hook0; uintptr_t spare_hook1; uintptr_t spare_hook2; uintptr_t spare_hook3; uintptr_t spare_hook4; uintptr_t spare_hook5; uintptr_t spare_hook6; uintptr_t spare_hook7;};

對于ngx_module_t結(jié)構(gòu)體的前7個(gè)成員,我們用Nginx提供的宏NGX_MODULE_V1進(jìn)行初始化。

#define NGX_MODULE_V1 \\ NGX_MODULE_UNSET_INDEX, NGX_MODULE_UNSET_INDEX, \\ NULL, 0, 0, nginx_version, NGX_MODULE_SIGNATURE

對于ngx_module_t結(jié)構(gòu)體的最后8個(gè)成員,我們用Nginx提供的宏NGX_MODULE_V1_PADDING進(jìn)行初始化。

#define NGX_MODULE_V1_PADDING 0, 0, 0, 0, 0, 0, 0, 0

對于在七個(gè)階段會(huì)調(diào)用的函數(shù)指針,我們的http_hello_module并不需要,所以統(tǒng)一設(shè)置為NULL。

因?yàn)槲覀兊睦邮且粋€(gè)http模塊,因此type值,等于NGX_HTTP_MODULE。

通過以上分析可知,為了定義結(jié)構(gòu)體ngx_module_s的對象,我們只需要定義以下兩個(gè)結(jié)構(gòu)體的對象:

結(jié)構(gòu)體ngx_http_module_t的對象,賦值給ctx,用于告知Nginx框架,我們的自定義模塊如何處理客戶端的請求結(jié)構(gòu)體ngx_command_t的數(shù)組對象,賦值給commands,用于告知Nginx框架,我們的自定義模塊需要的配置項(xiàng)ngx_module_s的成員commands定義

對于有配置項(xiàng)的模塊,需要定義一個(gè)結(jié)構(gòu)體,用于存儲(chǔ)配置項(xiàng)的值。本例中,我們需要兩個(gè)配置項(xiàng), hello_string和hello_counter,分別是string和int類型,因此,存儲(chǔ)配置項(xiàng)的結(jié)構(gòu)體定義如下。

typedef struct{ ngx_str_t hello_string; ngx_int_t hello_counter;} ngx_http_hello_loc_conf_t;

有一點(diǎn)需要注意的是,在模塊的開發(fā)過程中,我們最好使用 Nginx 原有的命名習(xí)慣。這樣跟源代碼的契合度更高,看起來也更舒服。對于模塊配置信息的定義,命名習(xí)慣是ngx_http_<module name>_(main|srv|loc)_conf_t。

commands數(shù)組用于定義模塊的配置文件參數(shù),每一個(gè)數(shù)組都是ngx_command_t類型,數(shù)組的結(jié)尾用ngx_null_command表示。Nginx框架在解析配置文件時(shí),對于一個(gè)配置項(xiàng),會(huì)遍歷所有的模塊。對每一個(gè)模塊,都會(huì)遍歷該模塊的commmands數(shù)組,直到遇到ngx_null_command。

ngx_command_t結(jié)構(gòu)體定義了自己感興趣的一個(gè)配置項(xiàng):

typedef struct ngx_command_s ngx_command_t;struct ngx_command_s { ngx_str_t name; ngx_uint_t type; char *(*set)(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); ngx_uint_t conf; ngx_uint_t offset; void *post; };

結(jié)構(gòu)體各成員的說明如下:

name: 配置指令的名稱。type: 配置項(xiàng)類型,該配置項(xiàng)可以出現(xiàn)的位置,如:server{}或location{},以及它可以攜帶的參數(shù)個(gè)數(shù)。例如:NGX_HTTP_LOC_CONF|NGX_CONF_NOARGS|NGX_CONF_TAKE1 表示該配置項(xiàng)出現(xiàn)在location位置,接收0個(gè)或1個(gè)參數(shù)。set:是一個(gè)函數(shù)指針。出現(xiàn)了name中指定的配置項(xiàng)后,將會(huì)調(diào)用set方法處理配置項(xiàng)的參數(shù)conf: 該字段指定當(dāng)前配置項(xiàng)存儲(chǔ)的內(nèi)存位置。因?yàn)?http 模塊對所有 http 模塊所要保存的配置信息,劃分了 main, server 和 location 三個(gè)地方進(jìn)行存儲(chǔ),每個(gè)地方都有一個(gè)內(nèi)存池用來分配存儲(chǔ)這些信息的內(nèi)存。這里可能的值為 NGX_HTTP_MAIN_CONF_OFFSET、NGX_HTTP_SRV_CONF_OFFSET 或 NGX_HTTP_LOC_CONF_OFFSET。offset: 指定該配置項(xiàng)值的精確存放位置,一般指定為某一個(gè)結(jié)構(gòu)體變量的字段偏移。post: 配置項(xiàng)讀取后的處理方法

因?yàn)槲覀兊睦佑袃蓚€(gè)配置項(xiàng),因此依次定義了兩個(gè)ngx_command_t,數(shù)組用ngx_null_command結(jié)尾。

static ngx_command_t ngx_http_hello_commands[] = { { ngx_string("hello_string"), // 配置項(xiàng)名字 NGX_HTTP_LOC_CONF|NGX_CONF_NOARGS|NGX_CONF_TAKE1, // 配置項(xiàng)出現(xiàn)的位置和接收的參數(shù)個(gè)數(shù) ngx_http_hello_string, // 在配置文件中讀到該配置項(xiàng)后,用該函數(shù)處理配置項(xiàng) NGX_HTTP_LOC_CONF_OFFSET, // 配置項(xiàng)的值,用LOCATION的內(nèi)存池存儲(chǔ) offsetof(ngx_http_hello_loc_conf_t, hello_string), // 存儲(chǔ)的精確位置 NULL }, { ngx_string("hello_counter"), NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, ngx_http_hello_counter, NGX_HTTP_LOC_CONF_OFFSET, offsetof(ngx_http_hello_loc_conf_t, hello_counter), NULL }, ngx_null_command};

對于hello_string配置項(xiàng),它的處理函數(shù)實(shí)現(xiàn)如下,ngx_conf_set_str_slot是Nginx提供的函數(shù),讀取string類型的配置項(xiàng)。

static char *ngx_http_hello_string(ngx_conf_t *cf, ngx_command_t *cmd, void *conf){ ngx_http_hello_loc_conf_t* local_conf; local_conf = conf; char* rv = ngx_conf_set_str_slot(cf, cmd, conf); return rv;}

對于hello_counter配置項(xiàng),他的處理函數(shù)實(shí)現(xiàn)如下,ngx_conf_set_flag_slot是Nginx提供的函數(shù),讀取on/off值的配置項(xiàng)。

static char *ngx_http_hello_counter(ngx_conf_t *cf, ngx_command_t *cmd, void *conf){ ngx_http_hello_loc_conf_t* local_conf; local_conf = conf; char* rv = NULL; rv = ngx_conf_set_flag_slot(cf, cmd, conf); return rv;}ngx_module_s的成員ctx定義

ctx是結(jié)構(gòu)體ngx_http_module_t的對象指針,主要用于定義在讀取配置文件的各個(gè)階段的處理函數(shù)。

下面展示的代碼,便是ngx_http_module_t這個(gè)結(jié)構(gòu)體:

typedef struct { // 解析配置文件前調(diào)用 ngx_int_t (*preconfiguration)(ngx_conf_t *cf); // 完成配置文件的解析后調(diào)用 ngx_int_t (*postconfiguration)(ngx_conf_t *cf); // 創(chuàng)建數(shù)據(jù)結(jié)構(gòu),用于存儲(chǔ)main級(jí)別(直屬于http{...}塊的配置項(xiàng))的全局配置項(xiàng) void *(*create_main_conf)(ngx_conf_t *cf); // 初始化用于main級(jí)別的配置項(xiàng) char *(*init_main_conf)(ngx_conf_t *cf, void *conf); //創(chuàng)建數(shù)據(jù)結(jié)構(gòu),用于存儲(chǔ)srv級(jí)別(直屬于虛擬主機(jī)server{...}塊的配置項(xiàng))的配置項(xiàng) void *(*create_srv_conf)(ngx_conf_t *cf); //合并main和srv級(jí)別下的同名配置項(xiàng) char *(*merge_srv_conf)(ngx_conf_t *cf, void *prev, void *conf); // 創(chuàng)建數(shù)據(jù)結(jié)構(gòu),用于存儲(chǔ)loc級(jí)別(直屬于location{...}塊的配置項(xiàng))的配置項(xiàng) void *(*create_loc_conf)(ngx_conf_t *cf); // 合并srv和location級(jí)別下的同名配置項(xiàng) char *(*merge_loc_conf)(ngx_conf_t *cf, void *prev, void *conf); } ngx_http_module_t;

在我們的例子中,ngx_http_module_t的各個(gè)字段的實(shí)現(xiàn)如下, 我們只關(guān)心location配置項(xiàng)的讀取以及在配置文件解析完成后的處理。location配置項(xiàng)讀取hello_string和hello_counter的值,配置文件解析完成后,我們掛載請求的處理函數(shù)。

static ngx_http_module_t ngx_http_hello_module_ctx = { NULL, /* preconfiguration */ ngx_http_hello_init, /* postconfiguration */ NULL, /* create main configuration */ NULL, /* init main configuration */ NULL, /* create server configuration */ NULL, /* merge server configuration */ ngx_http_hello_create_loc_conf, /* create location configuration */ NULL /* merge location configuration */};

我們先來看一下ngx_http_hello_create_loc_conf是如何存儲(chǔ)loc級(jí)別的配置項(xiàng)。 ngx_http_hello_create_loc_conf是告訴Ngixn模塊,我們使用的loc級(jí)別的配置項(xiàng)的信息,并對配置項(xiàng)進(jìn)行初始化。

static void *ngx_http_hello_create_loc_conf(ngx_conf_t *cf){ ngx_http_hello_loc_conf_t* local_conf = NULL; local_conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_hello_loc_conf_t)); if (local_conf == NULL) { return NULL; } ngx_str_null(&local_conf->hello_string); local_conf->hello_counter = NGX_CONF_UNSET; return local_conf;}

在配置文件處理完后,我們掛載模塊的處理函數(shù)。即告訴Nginx框架,當(dāng)符合條件的請求過來時(shí),我們自定義的模塊如何處理請求,如何響應(yīng)請求。掛載是在配置文件解析完畢,由函數(shù)ngx_http_hello_init完成的。

static ngx_int_tngx_http_hello_init(ngx_conf_t *cf){ ngx_http_handler_pt *h; ngx_http_core_main_conf_t *cmcf; cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module); h = ngx_array_push(&cmcf->phases[NGX_HTTP_CONTENT_PHASE].handlers); if (h == NULL) { return NGX_ERROR; } *h = ngx_http_hello_handler; return NGX_OK;}

從上述代碼可知,我們掛載的處理函數(shù)為ngx_http_hello_handler,即由它處理客戶端請求、做出具體響應(yīng)。

static ngx_int_tngx_http_hello_handler(ngx_http_request_t *r){ ngx_int_t rc; ngx_buf_t *b; ngx_chain_t out; ngx_http_hello_loc_conf_t* my_conf; u_char ngx_hello_string[1024] = {0}; ngx_uint_t content_length = 0; ngx_log_error(NGX_LOG_EMERG, r->connection->log, 0, "ngx_http_hello_handler is called!"); my_conf = ngx_http_get_module_loc_conf(r, ngx_http_hello_module); if (my_conf->hello_string.len == 0 ) { ngx_log_error(NGX_LOG_EMERG, r->connection->log, 0, "hello_string is empty!"); return NGX_DECLINED; } if (my_conf->hello_counter == NGX_CONF_UNSET || my_conf->hello_counter == 0) { ngx_sprintf(ngx_hello_string, "%s", my_conf->hello_string.data); } else { ngx_sprintf(ngx_hello_string, "%s Visited Times:%d", my_conf->hello_string.data, ++ngx_hello_visited_times); } ngx_log_error(NGX_LOG_EMERG, r->connection->log, 0, "hello_string:%s", ngx_hello_string); content_length = ngx_strlen(ngx_hello_string); /* we response to 'GET' and 'HEAD' requests only */ if (!(r->method & (NGX_HTTP_GET|NGX_HTTP_HEAD))) { return NGX_HTTP_NOT_ALLOWED; } /* discard request body, since we don't need it here */ rc = ngx_http_discard_request_body(r); if (rc != NGX_OK) { return rc; } ngx_str_set(&r->headers_out.content_type, "text/html"); /* send the header only, if the request type is http 'HEAD' */ if (r->method == NGX_HTTP_HEAD) { r->headers_out.status = NGX_HTTP_OK; r->headers_out.content_length_n = content_length; return ngx_http_send_header(r); } /* allocate a buffer for your response body */ b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t)); if (b == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } /* attach this buffer to the buffer chain */ out.buf = b; out.next = NULL; /* adjust the pointers of the buffer */ b->pos = ngx_hello_string; b->last = ngx_hello_string + content_length; b->memory = 1; /* this buffer is in memory */ b->last_buf = 1; /* this is the last buffer in the buffer chain */ /* set the status line */ r->headers_out.status = NGX_HTTP_OK; r->headers_out.content_length_n = content_length; /* send the headers of your response */ rc = ngx_http_send_header(r); if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) { return rc; } /* send the buffer chain of your response */ return ngx_http_output_filter(r, &out);}如何把http_hello_module編譯進(jìn)Nginx

上面介紹了,編寫一個(gè)http模塊的基本要素。接下來,介紹如何把這個(gè)簡單的模塊編譯進(jìn)Nginx框架,從而讓它發(fā)揮作用。

方案一:在執(zhí)行configure命令時(shí),添加--add-module參數(shù)

Nginx提供了一種簡單的方式將第三方的模塊編譯進(jìn)Nginx中。首先是把第三方的源代碼全部放在一個(gè)目錄中, 并在該目錄下新建一個(gè)名為config的文件,這個(gè)config文件的目的,就是告訴Nginx如何編譯我們自己的模塊。在執(zhí)行Nginx的configure命令時(shí), 加入?yún)?shù) --add-module=PATH,PATH就是我們存放config的目錄,就可以把我們開發(fā)的http_hello_module編譯進(jìn)Nginx。

我們的http_hello_module是一個(gè)http模塊,因此config文件中只需要定義以下三個(gè)變量:

ngx_addon_name: 僅在configure執(zhí)行時(shí)使用,一般設(shè)置為模塊名稱。HTTP_MODULES: 添加自定義模塊的名稱。NGX_ADDON_SRCS:指定新增模塊的源代碼。如果有多個(gè)文件,則以空格隔開。

我們的http_hello_module例子,它的config文件完整內(nèi)容如下。$ngx_addon_dir變量的值,等于我們在執(zhí)行configure命令時(shí),參數(shù)--add-module的值。

ngx_addon_name=ngx_http_hello_moduleHTTP_MODULES="$HTTP_MODULES ngx_http_hello_module"NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/ngx_http_hello_module.c"

因?yàn)槲覀儽纠蔷帉懸粋€(gè)http module,因此賦值了HTTP_MODULES。如果是編寫其他模塊,如http 過濾模塊、Nginx核心模塊、事件模塊、http頭部過濾模塊,則應(yīng)該分別對變量HTTP_FILTER_MODULES、CORE_MODULES、EVENT_MODULES、HTTP_HEADER_FILTER_MODULES。

方案二:在執(zhí)行configure命令后,修改Makefile文件

Nginx提供的另一種方法是直接修改Makefile文件。在執(zhí)行完configure腳本后,會(huì)在objs/Makefile和objs/ngx_modules.c文件。我們可以直接修改這兩個(gè)文件,從而完成http_hello_module編譯進(jìn)Nginx的目標(biāo)。

以上就是關(guān)于pos機(jī)模塊無應(yīng)答,寫一個(gè)Nginx的模塊沒有那么難的知識(shí),后面我們會(huì)繼續(xù)為大家整理關(guān)于pos機(jī)模塊無應(yīng)答的知識(shí),希望能夠幫助到大家!

轉(zhuǎn)發(fā)請帶上網(wǎng)址:http://m.afbey.com/news/19308.html

你可能會(huì)喜歡:

版權(quán)聲明:本文內(nèi)容由互聯(lián)網(wǎng)用戶自發(fā)貢獻(xiàn),該文觀點(diǎn)僅代表作者本人。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如發(fā)現(xiàn)本站有涉嫌抄襲侵權(quán)/違法違規(guī)的內(nèi)容, 請發(fā)送郵件至 babsan@163.com 舉報(bào),一經(jīng)查實(shí),本站將立刻刪除。