




版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)
文檔簡介
1、Emiller的模塊開發(fā)指南作者:Evan Miller 草稿: July 14, 2008 (HYPERLINK /nginx-modules-guide.html l changeschanges)譯者:YaoWeibin 草稿:Sep 20,2008 TOC o 1-3 h z u HYPERLINK l _Toc209691245 0. 預(yù)備知識 PAGEREF _Toc209691245 h 1 HYPERLINK l _Toc209691246 1. Nginx模塊任務(wù)委派的主要輪廓 PAGEREF _Toc209691246 h 1 HYPERLINK l _Toc2096912
2、47 2. Nginx模塊的組成 PAGEREF _Toc209691247 h 3 HYPERLINK l _Toc209691248 2.1. 模塊的配置結(jié)構(gòu)體 PAGEREF _Toc209691248 h 3 HYPERLINK l _Toc209691249 2.2. 模塊的指令 PAGEREF _Toc209691249 h 3 HYPERLINK l _Toc209691250 2.3. 模塊的上下文 PAGEREF _Toc209691250 h 6 HYPERLINK l _Toc209691251 2.3.1. create_loc_conf PAGEREF _Toc209
3、691251 h 7 HYPERLINK l _Toc209691252 2.3.2. merge_loc_conf PAGEREF _Toc209691252 h 8 HYPERLINK l _Toc209691253 2.4. 模塊定義 PAGEREF _Toc209691253 h 9 HYPERLINK l _Toc209691254 2.5. 模塊注冊 PAGEREF _Toc209691254 h 9 HYPERLINK l _Toc209691255 2.5.1.處理模塊的注冊 PAGEREF _Toc209691255 h 10 HYPERLINK l _Toc20969125
4、6 2.5.2. 過濾模塊的注冊 PAGEREF _Toc209691256 h 10 HYPERLINK l _Toc209691257 3. 處理模塊、過濾模塊和 負(fù)載均衡模塊 PAGEREF _Toc209691257 h 11 HYPERLINK l _Toc209691258 3.1. 剖析處理模塊(非代理) PAGEREF _Toc209691258 h 12 HYPERLINK l _Toc209691259 3.1.1. 獲得位置配置結(jié)構(gòu)體 PAGEREF _Toc209691259 h 12 HYPERLINK l _Toc209691260 3.1.2. 產(chǎn)生回復(fù) PAGE
5、REF _Toc209691260 h 12 HYPERLINK l _Toc209691261 3.1.3. 發(fā)送HTTP頭部 PAGEREF _Toc209691261 h 13 HYPERLINK l _Toc209691262 3.1.4. 發(fā)送HTTP負(fù)載 PAGEREF _Toc209691262 h 14 HYPERLINK l _Toc209691263 3.2. 上游模塊剖析(又稱代理模塊) PAGEREF _Toc209691263 h 15 HYPERLINK l _Toc209691264 3.2.1.代理模塊回調(diào)函數(shù)的概要 PAGEREF _Toc209691264
6、h 16 HYPERLINK l _Toc209691265 3.2.2. create_request 回調(diào)函數(shù) PAGEREF _Toc209691265 h 17 HYPERLINK l _Toc209691266 3.2.3. process_header 回調(diào)函數(shù) PAGEREF _Toc209691266 h 18 HYPERLINK l _Toc209691267 3.2.4. 狀態(tài)保持 PAGEREF _Toc209691267 h 19 HYPERLINK l _Toc209691268 3.3. 剖析頭部過濾函數(shù) PAGEREF _Toc209691268 h 20 HYP
7、ERLINK l _Toc209691269 3.4. 剖析負(fù)載過濾函數(shù) PAGEREF _Toc209691269 h 21 HYPERLINK l _Toc209691270 3.5. 剖析負(fù)載均衡模塊 PAGEREF _Toc209691270 h 22 HYPERLINK l _Toc209691271 3.5.1.激活指令 PAGEREF _Toc209691271 h 23 HYPERLINK l _Toc209691272 3.5.2.注冊函數(shù) PAGEREF _Toc209691272 h 23 HYPERLINK l _Toc209691273 3.5.3.上游主機(jī)初始化函數(shù)
8、 PAGEREF _Toc209691273 h 25 HYPERLINK l _Toc209691274 3.5.4.同伴初始化函數(shù) PAGEREF _Toc209691274 h 26 HYPERLINK l _Toc209691275 3.5.5.負(fù)載均衡函數(shù) PAGEREF _Toc209691275 h 28 HYPERLINK l _Toc209691276 3.5.6. 同伴釋放函數(shù) PAGEREF _Toc209691276 h 29 HYPERLINK l _Toc209691277 4. Advanced Topics PAGEREF _Toc209691277 h 30
9、HYPERLINK l _Toc209691278 4.1. Shared Memory PAGEREF _Toc209691278 h 30 HYPERLINK l _Toc209691279 4.1.1. A (fore)word of caution PAGEREF _Toc209691279 h 31 HYPERLINK l _Toc209691280 4.1.2. Creating and using a shared memory segment PAGEREF _Toc209691280 h 31 HYPERLINK l _Toc209691281 4.1.3. Using th
10、e slab allocator PAGEREF _Toc209691281 h 33 HYPERLINK l _Toc209691282 4.1.4. Spinlocks, atomic memory access PAGEREF _Toc209691282 h 34 HYPERLINK l _Toc209691283 4.1.5. Using rbtrees PAGEREF _Toc209691283 h 35 HYPERLINK l _Toc209691284 4.2. Subrequests PAGEREF _Toc209691284 h 36 HYPERLINK l _Toc2096
11、91285 4.2.1. Internal redirects PAGEREF _Toc209691285 h 36 HYPERLINK l _Toc209691286 4.2.2. A single subrequest PAGEREF _Toc209691286 h 36 HYPERLINK l _Toc209691287 4.2.3. Sequential subrequests PAGEREF _Toc209691287 h 38 HYPERLINK l _Toc209691288 4.2.4. Parallel subrequests PAGEREF _Toc209691288 h
12、40 HYPERLINK l _Toc209691289 4.3. TODO: Advanced Topics Not Yet Covered Here PAGEREF _Toc209691289 h 40 HYPERLINK l _Toc209691290 5. Writing and Compiling a New Nginx Module PAGEREF _Toc209691290 h 41 HYPERLINK l _Toc209691291 Appendix A: Code References PAGEREF _Toc209691291 h 42 HYPERLINK l _Toc20
13、9691292 Appendix B: Changelog PAGEREF _Toc209691292 h 42翻譯說明:在Nginx的模塊編寫過程中,時??嘤谖臋n的不足,而源代碼中又沒多少注釋。感謝Emiller的這篇英文文檔帶我入門。這次我翻譯的是一至三章,希望能給中國廣大Nginxer能有幫助,對于一般的應(yīng)用來說,前三章的內(nèi)容就足夠了。如果時間夠的話,我可能也會翻譯第四章。由于英語水平一般,接觸Nginx時間不多,翻譯中碰到的錯誤在所難免,如果您覺得哪里翻譯得不對,請跟我聯(lián)系:翻譯詞匯對照表:Backend:后端備選服務(wù)器。Buffer:緩沖區(qū)。Callback:回調(diào)函數(shù),一般來說是將某
14、個回調(diào)函數(shù)賦值給某個函數(shù)指針CHAIN OF RESPONSIBILITY:接力鏈表。Filter:過濾模塊/函數(shù),模塊和函數(shù)的概念似乎有點(diǎn)模糊不清。Handler: 處理模塊/函數(shù),另外也有指向具體的處理函數(shù)的指針或句柄的意思。Installation:愿意為安裝,我覺得還是譯作注冊好點(diǎn)。Load-balancer:負(fù)載均衡模塊/函數(shù)。Location:指URL位置,比如中的“/photo”目錄。Master:主進(jìn)程,由主進(jìn)程產(chǎn)生worker進(jìn)程,同時也可以而監(jiān)視worker進(jìn)程的動態(tài),worker因?yàn)楫惓6顺龅臅r候也可以重啟一個新的worker進(jìn)程。Reference:一般譯作“引用”,
15、不過很多時候,似乎還不如稱作“指針”來的直接些。Request:HTTP 請求。Response:HTTP 回復(fù)。Server-side:服務(wù)端。Upstream:上游服務(wù)(器),有時亦稱backend。Worker:工作進(jìn)程,模塊真正發(fā)揮作用的地方。0. 預(yù)備知識對于C語言,你應(yīng)該熟悉。不僅是會C的語法,對于結(jié)構(gòu)體和預(yù)處理命令你應(yīng)該有深入的理解,特別見到大量的指針和函數(shù)引用的時候不會驚慌失措。如果覺得需要補(bǔ)習(xí),就多看看K&R(C語言的語法書)。如果你對于HTTP協(xié)議已經(jīng)有了基本概念,那是很有好處的。畢竟你正在Web服務(wù)上工作。你應(yīng)該熟悉Nginx的配置文件。如果不熟悉,也沒關(guān)系,這里有一些基
16、本理解:Nginx配置文件主要分成四部分:main(全局設(shè)置)、server(主機(jī)設(shè)置)、upstream(上游服務(wù)器設(shè)置)和location(URL匹配特定位置后的設(shè)置)。每部分包含若干個指令。main部分設(shè)置的指令將影響其它所有部分;server部分的指令主要用于指定主機(jī)和端口;upstream的指令用于設(shè)置后端服務(wù)器;location部分用于匹配網(wǎng)頁位置(比如,根目錄“/”,“/images”,等等)。Location部分會繼承server部分的指令,而server部分的指令會繼承main部分;upstream既不會繼承指令也不會影響其他部分。它有自己的特殊指令,不需要在其他地方的應(yīng)用。
17、在下面很多地方都會涉及這四個部分,不要忘記喲。讓我們開始吧。1. Nginx模塊任務(wù)委派的主要輪廓Nginx模塊主要有3種角色:handlers(處理模塊) 用于處理HTTP請求,然后產(chǎn)生輸出 filters(過濾模塊) 過濾handler產(chǎn)生的輸出 load-balancers(負(fù)載均衡模塊)當(dāng)有多于一臺的后端備選服務(wù)器時,選擇一臺轉(zhuǎn)發(fā)HTTP請求模塊可以做任何你分配給web服務(wù)器的實(shí)際工作:當(dāng)Nginx發(fā)送文件或者轉(zhuǎn)發(fā)請求到其他服務(wù)器,有處理模塊為其服務(wù);當(dāng)需要Nginx把輸出壓縮或者在服務(wù)端加一些東西,可以用過濾模塊;Nginx的核心模塊主要管理網(wǎng)絡(luò)層和應(yīng)用層協(xié)議,以及啟動針對特定應(yīng)用的
18、一系列候選模塊。集中式的體系結(jié)構(gòu)讓你可以隨心所欲得實(shí)現(xiàn)一些功能強(qiáng)大的內(nèi)部單元。注意:Nginx不像apache,模塊不是動態(tài)添加的(換句話就是說,所有的模塊都要預(yù)先編譯進(jìn)Nginx的二進(jìn)制可執(zhí)行文件)。模塊是如何被調(diào)用的?典型的講,當(dāng)服務(wù)器啟動,每個處理模塊都有機(jī)會映射到配置文件中定義的特定位置;如果有多個處理模塊映射到特定位置時,只有一個會“贏”(但聰明如你,當(dāng)然不會讓這些沖突產(chǎn)生)。處理模塊以三種形式返回:OK、ERROR、或者放棄處理這個請求而讓默認(rèn)處理模塊來處理(主要是用來處理一些靜態(tài)文件,事實(shí)上如果是位置正確而真實(shí)的靜態(tài)文件,默認(rèn)的處理模塊會搶先處理)。如果處理模塊把請求反向代理到后
19、端的服務(wù)器,就變成另外一類的模塊:負(fù)載均衡模塊。負(fù)載均衡模塊的配置中有一組后端服務(wù)器,當(dāng)一個HTTP請求過來時,它決定哪臺服務(wù)器應(yīng)當(dāng)獲得這個請求。Nginx的負(fù)載均衡模塊采用兩種方法:輪轉(zhuǎn)法,它處理請求就像紙牌游戲一樣從頭到尾分發(fā);IP哈希法,在眾多請求的情況下,它確保來自同一個IP的請求會分發(fā)到相同的后端服務(wù)器。如果處理模塊沒有產(chǎn)生錯誤,過濾模塊將被調(diào)用。多個過濾模塊能映射到每個位置,所以(比如)每個請求都可以被壓縮成塊。它們的執(zhí)行順序在編譯時決定。過濾模塊是經(jīng)典的“接力鏈表(CHAIN OF RESPONSIBILITY)”模型:一個過濾模塊被調(diào)用,完成其工作,然后調(diào)用下一個過濾模塊,直到
20、最后一個過濾模塊。Nginx完成這個回復(fù)。真正cool的地方是在過濾模塊鏈中,每個過濾模塊不會等上一個過濾模塊全部完成;它能把前一個過濾模塊的輸出作為其處理內(nèi)容;有點(diǎn)像Unix中的流水線。過濾模塊能以buffer(緩沖區(qū))為單位進(jìn)行操作,這些buffer一般都是一頁(4K)大小,當(dāng)然你也可以在nginx.conf文件中進(jìn)行配置。這意味著,比如,模塊可以壓縮來自后端服務(wù)器的回復(fù),然后像流一樣的到達(dá)客戶端,直到整個回復(fù)發(fā)送完成。所以總結(jié)下上面的內(nèi)容,一個典型的處理周期是這樣的:客戶端發(fā)送HTTP請求-Nginx基于配置文件中的位置選擇一個合適的處理模塊-(如果有)負(fù)載均衡模塊選擇一臺后端服務(wù)器-處
21、理模塊進(jìn)行處理并把輸出緩沖放到第一個過濾模塊上-第一個過濾模塊處理后輸出給第二個過濾模塊-然后第二個過濾模塊又到第三個-依此類推-最后把回復(fù)發(fā)給客戶端。我說“典型”這個詞是因?yàn)镹ginx的模塊調(diào)用是具有很強(qiáng)的定制性的。模塊開發(fā)者需要花很多精力精確定義模塊在何時如何產(chǎn)生作用(我認(rèn)為是件不容易的事)。模塊的調(diào)用事實(shí)上通過一系列的回調(diào)函數(shù)來實(shí)現(xiàn),很多很多。名義上來說,你的函數(shù)可在以下時段執(zhí)行某些功能:當(dāng)服務(wù)讀配置文件之前讀存在location和server或其他任何部分的每一個配置指令當(dāng)Nginx初始化全局部分的配置時當(dāng)Nginx初始化主機(jī)部分(比如主機(jī)/端口)的配置時當(dāng)Nginx將全局部分的配置與
22、主機(jī)部分的配置合并的時候當(dāng)Nginx初始化匹配位置部分配置的時候當(dāng)Nginx將其上層主機(jī)配置與位置部分配置合并的時候當(dāng)Nginx的主(master)進(jìn)程開始的時候當(dāng)一個新的工作進(jìn)程(worker)開始的時候當(dāng)一個工作進(jìn)程退出的時候當(dāng)主進(jìn)程退出的時候處理HTTP請求過濾HTTP回復(fù)的頭部過濾HTTP回復(fù)的主體選擇一臺后端服務(wù)器初始化到后端服務(wù)器的請求重新初始化到后端的服務(wù)器的請求處理來自后端服務(wù)器的回復(fù)完成與后端服務(wù)器的交互難以置信!有這么多的功能任你處置,而你只需僅僅通過多組有用的鉤子(由函數(shù)指針組成的結(jié)構(gòu)體)和相應(yīng)的實(shí)現(xiàn)函數(shù)。讓我們開始接觸一些模塊吧。2. Nginx模塊的組成我說過, Ng
23、inx模塊的使用是很靈活的。本段描述的東西會經(jīng)常出現(xiàn)。它引導(dǎo)你理解模塊,也可以成為你開始寫模塊的參考。2.1. 模塊的配置結(jié)構(gòu)體模塊的配置結(jié)構(gòu)體的定義有三種,分別是全局,主機(jī)和位置的配置結(jié)構(gòu)體。大多數(shù)模塊僅僅需要一個位置的配置結(jié)構(gòu)體。名稱約定是這樣的:ngx_http_(main|srv|loc)_conf_t。這里有一個來自dav模塊的列子:typedef struct ngx_uint_t methods; ngx_flag_t create_full_put_path; ngx_uint_t access; ngx_http_dav_loc_conf_t;注意Nginx有一些特別的類型(
24、如:ngx_uint_t 和 ngx_flag_t);這些可能是一些基本類型的別名。(如果你好奇的話,可以看這里:HYPERLINK /lxr/http/source/core/ngx_config.h l L79core/ngx_config.h)這些類型用在配置結(jié)構(gòu)體中出現(xiàn)的情形很多。2.2. 模塊的指令模塊的指令出現(xiàn)在靜態(tài)數(shù)組ngx_command_t。這里有一個例子,說明它們是如何被定義的,來自我寫的一個小模塊:static ngx_command_t ngx_http_circle_gif_commands = ngx_string(circle_gif), NGX_HTTP_LOC
25、_CONF|NGX_CONF_NOARGS, ngx_http_circle_gif, NGX_HTTP_LOC_CONF_OFFSET, 0, NULL , ngx_string(circle_gif_min_radius), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, ngx_conf_set_num_slot, NGX_HTTP_LOC_CONF_OFFSET, offsetof(ngx_http_circle_gif_loc_conf_t, min_radius), NULL , . ng
26、x_null_command;這是ngx_command_t 的函數(shù)原型(也就是我們定義的那些結(jié)構(gòu)體),出自HYPERLINK /lxr/http/source/core/ngx_conf_file.h l L77core/ngx_conf_file.h :struct ngx_command_t 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;參數(shù)多了點(diǎn),但每
27、個參數(shù)都是有用的:name是指令的字符串(也就是包含指令名稱),不包含空格(有空格的話就是另外命令的參數(shù)了)。數(shù)據(jù)類型是ngx_str_t,經(jīng)常用來進(jìn)行字符串實(shí)例化(比如:ngx_str(proxy_pass))。注意:ngx_str_t結(jié)構(gòu)體由包含有字符串的data成員和表示字符串長度的len成員組成。Nginx用這個數(shù)據(jù)類型來存放字符串。type是標(biāo)識的集合,表明這個指令在哪里出現(xiàn)是合法的、指令的參數(shù)個數(shù)。應(yīng)用中,標(biāo)識一般是下面多個值的位或:NGX_HTTP_MAIN_CONF: 指令出現(xiàn)在全局配置部分是合法的NGX_HTTP_SRV_CONF: 指令在主機(jī)配置部分出現(xiàn)是合法的 NGX_H
28、TTP_LOC_CONF: 指令在位置配置部分出現(xiàn)是合法的 NGX_HTTP_UPS_CONF: 指令在上游服務(wù)器配置部分出現(xiàn)是合法的 NGX_CONF_NOARGS: 指令沒有參數(shù) NGX_CONF_TAKE1: 指令讀入一個參數(shù) NGX_CONF_TAKE2: 指令讀入兩個參數(shù). NGX_CONF_TAKE7: 指令讀入七個參數(shù)NGX_CONF_FLAG: 指令讀入一個布爾型數(shù)據(jù) NGX_CONF_1MORE: 指令至少讀入1個參數(shù)NGX_CONF_2MORE: 指令至少讀入2個參數(shù) 這里有很多另外的選項(xiàng):core/ngx_conf_file.h。結(jié)構(gòu)體成員set是一個函數(shù)指針,用來設(shè)定模
29、塊的配置;典型地,這個函數(shù)會轉(zhuǎn)化指令傳進(jìn)來的參數(shù),然后將合適的值保存到配置結(jié)構(gòu)體。這個設(shè)定函數(shù)有三個參數(shù):指向ngx_conf_t結(jié)構(gòu)體的指針,包含從指令后面?zhèn)鬟^來的參數(shù)。指向當(dāng)前ngx_command_t結(jié)構(gòu)體的指針指向自定義模塊配置結(jié)構(gòu)體的指針這個設(shè)定函數(shù)在指令被遇到的時候就會調(diào)用。在自定義的配置結(jié)構(gòu)體中,Nginx提供了多個函數(shù)用來保存特定類型的數(shù)據(jù),這些函數(shù)包含有:ngx_conf_set_flag_slot: 將on或off轉(zhuǎn)化為 ngx_conf_set_str_slot: 將字符串保存位ngx_str_t類型 ngx_conf_set_num_slot: 解析一個數(shù)字并保存為in
30、t型ngx_conf_set_size_slot: 解析一個數(shù)據(jù)大小(如:8k, 1m) 并保存為 size_t類型還有另外一些,很容易查到(看,HYPERLINK /lxr/http/source/core/ngx_conf_file.h l L329core/ngx_conf_file.h)。模塊也可以把它們自己函數(shù)的引用放在這里,但這樣內(nèi)嵌的類型不是很好。那這些內(nèi)嵌函數(shù)怎么知道要把值保存在哪里呢?ngx_command_t接下來的兩個成員conf和offset正好可用。conf告訴Nginx把這個值是放在全局配置部分、主機(jī)配置部分還是位置配置部分呢(用NGX_HTTP_MAIN_CONF
31、_OFFSET, NGX_HTTP_SRV_CONF_OFFSET或NGX_HTTP_LOC_CONF_OFFSET)。然后offset確定到底是保存在結(jié)構(gòu)體的哪個位置。最后,post指向模塊在讀配置的時候需要的一些零碎變量。一般它是NULL。這個ngx_command_t 數(shù)組在讀入ngx_null_command 后停止,也即最后一個成員。2.3. 模塊的上下文靜態(tài)的ngx_http_module_t 結(jié)構(gòu)體,包含一大把的函數(shù)引用。用來創(chuàng)建三個部分的配置和合并配置。一般結(jié)構(gòu)體命名為ngx_http_module_ctx。以此,這些函數(shù)引用包括:在讀入配置前調(diào)用在讀入配置后調(diào)用在創(chuàng)建全局部分
32、配置時調(diào)用(比如,用來分配空間和設(shè)置默認(rèn)值)在初始化全局部分的配置時調(diào)用(比如,把原來的默認(rèn)值用nginx.conf讀到的值來覆蓋)在創(chuàng)建主機(jī)部分的配置時調(diào)用與全局部分配置合并時調(diào)用創(chuàng)建位置部分的配置時掉用與主機(jī)部分配置合并時調(diào)用這些函數(shù)參數(shù)不同,依賴與它們的功能。這里有這個結(jié)構(gòu)體的定義,摘自http/ngx_http_config.h,你可以看到屬性各不同的回調(diào)函數(shù):typedef struct ngx_int_t (*preconfiguration)(ngx_conf_t *cf); ngx_int_t (*postconfiguration)(ngx_conf_t *cf); void
33、 *(*create_main_conf)(ngx_conf_t *cf); char *(*init_main_conf)(ngx_conf_t *cf, void *conf); void *(*create_srv_conf)(ngx_conf_t *cf); char *(*merge_srv_conf)(ngx_conf_t *cf, void *prev, void *conf); void *(*create_loc_conf)(ngx_conf_t *cf); char *(*merge_loc_conf)(ngx_conf_t *cf, void *prev, void *c
34、onf); ngx_http_module_t;如果不用某些函數(shù),可以設(shè)定為NULL,Nginx會剔除它。大多數(shù)處理模塊只使用最后兩個:一個函數(shù)用來為特定的位置部分的配置結(jié)構(gòu)體分配內(nèi)存(稱為ngx_http_create_loc_conf),另外一個函數(shù)用來設(shè)定默認(rèn)值和與繼承過來的配置合并(稱為ngx_http_merge_loc_conf)。這個合并函數(shù)負(fù)責(zé)檢驗(yàn)讀入的數(shù)值是否有效,否則報錯;這些錯誤將會中止服務(wù)的運(yùn)行。這里有一個模塊上下文結(jié)構(gòu)體的例子:static ngx_http_module_t ngx_http_circle_gif_module_ctx = NULL, /* prec
35、onfiguration */ NULL, /* postconfiguration */ NULL, /* create main configuration */ NULL, /* init main configuration */ NULL, /* create server configuration */ NULL, /* merge server configuration */ ngx_http_circle_gif_create_loc_conf, /* create location configuration */ ngx_http_circle_gif_merge_lo
36、c_conf /* merge location configuration */;現(xiàn)在開始講得更深一點(diǎn)。這些配置回調(diào)函數(shù)看其來很像,所有模塊都一樣,而且Nginx的API都會用到這個部分,所以值得了解。2.3.1. create_loc_confcreate_loc_conf函數(shù)骨架看起來像這個樣子,摘自我寫的circle_gif模塊(看源代碼)。它的參數(shù)是結(jié)構(gòu)體ngx_conf_t ,返回更新的模塊配置結(jié)構(gòu)體(例子中是ngx_http_circle_gif_loc_conf_t)。static void *ngx_http_circle_gif_create_loc_conf(ngx_co
37、nf_t *cf) ngx_http_circle_gif_loc_conf_t *conf; conf = ngx_pcalloc(cf-pool, sizeof(ngx_http_circle_gif_loc_conf_t); if (conf = NULL) return NGX_CONF_ERROR; conf-min_radius = NGX_CONF_UNSET_UINT; conf-max_radius = NGX_CONF_UNSET_UINT; return conf;第一個需要注意的是Nginx的內(nèi)存分配,只要使用ngx_palloc(malloc的包裝函數(shù))或ngx_pc
38、alloc(calloc的包裝函數(shù))就不需要關(guān)心內(nèi)存的釋放。UNSET常量有:NGX_CONF_UNSET_UINT, NGX_CONF_UNSET_PTR, NGX_CONF_UNSET_SIZE, NGX_CONF_UNSET_MSEC, 和一起的NGX_CONF_UNSET。UNSET告訴合并函數(shù)這些值還沒有被初始化過,需要并覆蓋。2.3.2. merge_loc_conf這是用在circle_gif模塊的合并函數(shù):static char *ngx_http_circle_gif_merge_loc_conf(ngx_conf_t *cf, void *parent, void *chi
39、ld) ngx_http_circle_gif_loc_conf_t *prev = parent; ngx_http_circle_gif_loc_conf_t *conf = child; ngx_conf_merge_uint_value(conf-min_radius, prev-min_radius, 10); ngx_conf_merge_uint_value(conf-max_radius, prev-max_radius, 20); if (conf-min_radius max_radius min_radius) ngx_conf_log_error(NGX_LOG_EME
40、RG, cf, 0, max_radius must be equal or more than min_radius); return NGX_CONF_ERROR; return NGX_CONF_OK;首先需要注意的是Nginx為不同的類型提供了良好的合并函數(shù)(ngx_conf_merge_value);這些參數(shù)含義是:當(dāng)前參數(shù)變量如果第一個參數(shù)沒有被設(shè)置如果第一個和第二個參數(shù)都沒有設(shè)置時的默認(rèn)值結(jié)果會保存在第一個參數(shù)中。有效的合并函數(shù)包括ngx_conf_merge_size_value, ngx_conf_merge_msec_value,在HYPERLINK /lxr/http/s
41、ource/core/ngx_conf_file.h l L254core/ngx_conf_file.h里有完整的列出。有個問題:因?yàn)榈谝粋€參數(shù)是傳值的,這些值是如何寫到第一個參數(shù)中?回答:這些函數(shù)其實(shí)都是預(yù)處理命令(在真正編譯之前,它們會被擴(kuò)展成一些if語句)。注意錯誤是如何產(chǎn)生的;這些函數(shù)把錯誤信息寫到log文件中,然后返回NGX_CONF_ERROR。返回代碼會中止服務(wù)的啟動。(因?yàn)楸粯?biāo)識為NGX_LOG_EMERG,這些消息也會被會輸出到標(biāo)準(zhǔn)輸出;HYPERLINK /lxr/http/source/core/ngx_log.h l L1core/ngx_log.h有完整的日志級別。
42、)2.4. 模塊定義第二步,我們間接的介紹更多一層,結(jié)構(gòu)體ngx_module_t。這個結(jié)構(gòu)體變量命名為ngx_http_module。它包含有模塊的主要內(nèi)容和指令的執(zhí)行部分,也有一些回調(diào)函數(shù)(退出線程,退出進(jìn)程,等等)。這個模塊的定義是把數(shù)據(jù)處理關(guān)聯(lián)到特定模塊的關(guān)鍵。模塊的定義像這個樣子:ngx_module_t ngx_http_module = NGX_MODULE_V1, &ngx_http_module_ctx, /* module context */ ngx_http_commands, /* module directives */ NGX_HTTP_MODULE, /* mo
43、dule type */ NULL, /* init master */ NULL, /* init module */ NULL, /* init process */ NULL, /* init thread */ NULL, /* exit thread */ NULL, /* exit process */ NULL, /* exit master */ NGX_MODULE_V1_PADDING;僅僅替換掉合適的模塊名稱就可以了。在進(jìn)程/線程退出的時候,模塊可以添加一些回調(diào)函數(shù)來運(yùn)行,但大多數(shù)模塊為了簡單的原因而沒有使用。(這些回調(diào)函數(shù)的參數(shù),可以參考HYPERLINK /lxr/h
44、ttp/source/core/ngx_conf_file.h l L110core/ngx_conf_file.h.)2.5. 模塊注冊有兩種途徑來注冊(Installation)模塊:處理模塊經(jīng)常是通過指令的回調(diào)函數(shù)來注冊,過濾模塊通過模塊上下文結(jié)構(gòu)體中的postconfigration回調(diào)函數(shù)來注冊。最后,我們告訴Nginx如何找到這些代碼。(負(fù)載均衡模塊有點(diǎn)特殊,是個費(fèi)解的例子,具體可以看3.5節(jié))2.5.1.處理模塊的注冊處理模塊的注冊通過添加代碼到指令中的回調(diào)函數(shù)。比如,我的circle gif ngx_command_t結(jié)構(gòu)體看起來這樣的: ngx_string(circle_g
45、if), NGX_HTTP_LOC_CONF|NGX_CONF_NOARGS, ngx_http_circle_gif, 0, 0, NULL 回調(diào)函數(shù)是第三個成員,在這個例子中是ngx_http_circle_gif函數(shù)。須知這個回調(diào)函數(shù)參數(shù)分別是配置結(jié)構(gòu)體(ngx_conf_t,保存用戶的參數(shù)),相關(guān)的ngx_command_t結(jié)構(gòu)體,以及一個指向模塊自定義的配置結(jié)構(gòu)體。在我的circle gif 模塊,這個函數(shù)看來像這樣:static char *ngx_http_circle_gif(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) ngx
46、_http_core_loc_conf_t *clcf; clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module); clcf-handler = ngx_http_circle_gif_handler; return NGX_CONF_OK;函數(shù)中有兩步,獲得這個位置配置的“核心”結(jié)構(gòu)體,然后為它分配一個處理函數(shù)。是不是很簡單,呵呵。2.5.2. 過濾模塊的注冊過濾模塊通過配置后的函數(shù)(postconfigration)來注冊。它們一般包括兩種過濾函數(shù):頭部過濾函數(shù)(header filters)處理HTTP頭,負(fù)載
47、過濾函數(shù)(body filters)處理負(fù)載。它們的注冊在同一個位置。以chunked filter模塊為例,它的模塊上下文是這樣的:static ngx_http_module_t ngx_http_chunked_filter_module_ctx = NULL, /* preconfiguration */ ngx_http_chunked_filter_init, /* postconfiguration */ .;下面是ngx_http_chunked_filter_init函數(shù)做的一些事情:static ngx_int_tngx_http_chunked_filter_init(n
48、gx_conf_t *cf) ngx_http_next_header_filter = ngx_http_top_header_filter; ngx_http_top_header_filter = ngx_http_chunked_header_filter; ngx_http_next_body_filter = ngx_http_top_body_filter; ngx_http_top_body_filter = ngx_http_chunked_body_filter; return NGX_OK;這里到底做了些什么?如果你還記得,過濾模塊組成了一條“接力鏈表”。當(dāng)一個處理模塊產(chǎn)
49、生一個回復(fù),它會調(diào)用兩個函數(shù):ngx_http_output_filter,調(diào)用全局函數(shù)ngx_http_top_body_filter;ngx_http_send_header,調(diào)用全局函數(shù)ngx_top_header_filter。ngx_http_top_body_filter和ngx_http_top_header_filter是負(fù)載和頭部各自的“鏈表頭部”。在這個鏈上每個成員都有指向下一個成員的函數(shù)指針(這個指針稱為ngx_http_next_body_filter 和 ngx_http_next_header_filter)。當(dāng)一個過濾模塊執(zhí)行完成后,它就調(diào)用下一個過濾模塊,直到一
50、個特殊的“寫”過濾模塊被調(diào)用,它把整個HTTP包裹起來。在filter_init函數(shù)中,可以看到是把模塊本身添加到過濾模塊鏈中;它用next變量保存了一個指向舊的“top”過濾模塊,然后聲明自己是新的“top”過濾模塊。(所以,最后注冊進(jìn)過濾鏈的模塊是最先被執(zhí)行的。)作者邊注:這是如何正常工作的呢?原來每個過濾函數(shù)用下面的語句或者錯誤代碼返回:return ngx_http_next_body_filter(); 所以,如果過濾鏈表達(dá)到最后一個成員(特別定義的),就會返回一個OK。如果出現(xiàn)錯誤,整條鏈表會被縮短,Nginx產(chǎn)生合適的錯誤消息。這是一條單向鏈表,僅僅使用函數(shù)引用,就可以實(shí)現(xiàn)快速的
51、錯誤返回。聰明。3. 處理模塊、過濾模塊和 負(fù)載均衡模塊接下來我們把模塊的細(xì)節(jié)放到顯微鏡下面來看,它們到底怎么運(yùn)行的。3.1. 剖析處理模塊(非代理)處理模塊一般做四樣?xùn)|西:獲得位置配置結(jié)構(gòu)體,產(chǎn)生合適的回復(fù),發(fā)送HTTP頭部和發(fā)送HTTP負(fù)載。它只有一個變量-請求結(jié)構(gòu)體。這個結(jié)構(gòu)體有很多關(guān)于客戶端請求的有用信息,比如請求方法(request method),URI和請求頭部。我們會一步一步分析整個過程。3.1.1. 獲得位置配置結(jié)構(gòu)體這部分很簡單。所有你需要做的是根據(jù)當(dāng)前的請求結(jié)構(gòu)體和模塊定義,調(diào)用ngx_http_get_module_loc_conf,獲得當(dāng)前的配置結(jié)構(gòu)體。這是我寫的ci
52、rcle gif hanlder函數(shù)的相關(guān)部分。static ngx_int_tngx_http_circle_gif_handler(ngx_http_request_t *r) ngx_http_circle_gif_loc_conf_t *circle_gif_config; circle_gif_config = ngx_http_get_module_loc_conf(r, ngx_http_circle_gif_module); .現(xiàn)在我們就能訪問在合并函數(shù)中定義的各個變量。3.1.2. 產(chǎn)生回復(fù)這部分很有趣,也是模塊真正起作用的地方。請求結(jié)構(gòu)體在這里也很有用,特別是這些成員變量:
53、typedef struct ./* the memory pool, used in the ngx_palloc functions */ ngx_pool_t *pool; ngx_str_t uri; ngx_str_t args; ngx_http_headers_in_t headers_in;. ngx_http_request_t;uri 是請求的路徑,比如:/query.cgi。args 是在問號之后請求的參數(shù)(比如 name=john)。headers_in 有很多有用的東西,如cookie和瀏覽器信息,但很多模塊不需要。如果你感興趣,請看這里HYPERLINK /lxr/
54、http/source/http/ngx_http_request.h l L158http/ngx_http_request.h 。這里應(yīng)該有足夠的信息來產(chǎn)生有用的輸出。ngx_http_request_t結(jié)構(gòu)體的完整定義在HYPERLINK /lxr/http/source/http/ngx_http_request.h l L316http/ngx_http_request.h。3.1.3. 發(fā)送HTTP頭部回復(fù)頭部存在于被稱為headers_out的結(jié)構(gòu)體中。它包含在請求結(jié)構(gòu)體中。這個處理函數(shù)生成頭部變量,然后調(diào)用ngx_http_send_header(r)函數(shù),下面列出些有用的部分
55、:typedef stuct . ngx_uint_t status; size_t content_type_len; ngx_str_t content_type; ngx_table_elt_t *content_encoding; off_t content_length_n; time_t date_time; time_t last_modified_time;. ngx_http_headers_out_t;(另外一些你可以在這里找到: HYPERLINK /lxr/http/source/http/ngx_http_request.h l L220http/ngx_http_r
56、equest.h.)舉個例子,如果一個模塊把Content-Type需要設(shè)定為“image/gif”,Content-Length為100,然后返回200 OK的回復(fù),代碼將是這樣的: r-headers_out.status = NGX_HTTP_OK; r-headers_out.content_length_n = 100; r-headers_out.content_type.len = sizeof(image/gif) - 1; r-headers_out.content_type.data = (u_char *) image/gif; ngx_http_send_header(
57、r);上面的設(shè)定方式針對大多數(shù)參數(shù)都是有效的。但一些頭部的變量設(shè)定要比上面的例子要麻煩;比如,content_encoding含有類型(ngx_table_elt_t*),這時模塊必須為它分配內(nèi)存??梢杂靡粋€叫ngx_list_push的函數(shù)來做。它需要傳入一個ngx_list_t變量(與數(shù)組類似),然后返回一個list中的新成員(類型是ngx_table_elt_t)。下面的代碼把Content-Encoding設(shè)定為“deflate”,然后把頭部發(fā)出。 r-headers_out.content_encoding = ngx_list_push(&r-headers_out.headers
58、); if (r-headers_out.content_encoding = NULL) return NGX_ERROR; r-headers_out.content_encoding-hash = 1; r-headers_out.content_encoding-key.len = sizeof(Content-Encoding) - 1; r-headers_out.content_encoding-key.data = (u_char *) Content-Encoding; r-headers_out.content_encoding-value.len = sizeof(def
59、late) - 1; r-headers_out.content_encoding-value.data = (u_char *) deflate;ngx_http_send_header(r);當(dāng)頭部有多個值的時候,這個機(jī)制會經(jīng)常用到;它(理論上講)使得過濾模塊添加、刪除某個值而保留其他值的時候更加容易,在操縱字符串的時候,不需要把字符串重新排序。3.1.4. 發(fā)送HTTP負(fù)載現(xiàn)在模塊已經(jīng)產(chǎn)生了一個回復(fù),把它放到內(nèi)存中。需要為回復(fù)分配一塊特別的buffer,并把這個buffer連接到一個鏈表,然后調(diào)用“send body”函數(shù)發(fā)送。這些鏈表有什么用?在Nginx中,處理模塊和過濾模塊在處理完
60、成后產(chǎn)生的回復(fù)都包含在緩沖中,每次產(chǎn)生一個buffer;每個鏈表成員保存指向下一個成員的指針,如果是最后的buffer,就置為NULL。這里我們簡單地假定只有一個buffer成員。首先,模塊聲明一個buffer和一條鏈表: ngx_buf_t *b; ngx_chain_t out;第二步是分配緩沖,然后指向我們的回復(fù)數(shù)據(jù): b = ngx_pcalloc(r-pool, sizeof(ngx_buf_t); if (b = NULL) ngx_log_error(NGX_LOG_ERR, r-connection-log, 0, Failed to allocate response buf
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 航空運(yùn)輸合同書
- 公司內(nèi)部銷售承包合同
- 土地買賣居間服務(wù)合同
- 返聘勞務(wù)合同
- 工程建設(shè)項(xiàng)目委托招標(biāo)代理合同
- 舊機(jī)動車交易合同書
- 影視制作服務(wù)版權(quán)轉(zhuǎn)讓合同
- 山東特殊教育職業(yè)學(xué)院《口腔解剖生理學(xué)一》2023-2024學(xué)年第二學(xué)期期末試卷
- 山西工商學(xué)院《機(jī)器人學(xué)導(dǎo)論》2023-2024學(xué)年第二學(xué)期期末試卷
- 山東勞動職業(yè)技術(shù)學(xué)院《模具設(shè)計(jì)》2023-2024學(xué)年第二學(xué)期期末試卷
- 物理學(xué)科中的跨學(xué)科應(yīng)用
- 專題07 二次函數(shù)與幾何圖形綜合問題(復(fù)習(xí)講義)(原卷版)-二輪要點(diǎn)歸納與典例解析
- 高中語文統(tǒng)編版(部編版)必修下冊第六單元 大單元公開課一等獎創(chuàng)新教學(xué)設(shè)計(jì)
- 初三化學(xué)學(xué)情分析
- 人教版新教材高一上學(xué)期期末考試數(shù)學(xué)試卷及答案(共五套)
- TB10092-2017 鐵路橋涵混凝土結(jié)構(gòu)設(shè)計(jì)規(guī)范
- 化工原理-第三章-過濾課件
- 2023年通遼市中考數(shù)學(xué)試卷及答案
- 腸內(nèi)營養(yǎng)考評標(biāo)準(zhǔn)終
- Mysql 8.0 OCP 1Z0-908 CN-total認(rèn)證備考題庫(含答案)
- 三年級下冊音樂教學(xué)計(jì)劃含教學(xué)進(jìn)度安排活動設(shè)計(jì)word表格版
評論
0/150
提交評論