中文字幕日韩精品一区二区免费_精品一区二区三区国产精品无卡在_国精品无码专区一区二区三区_国产αv三级中文在线

Nginx源碼解析-http模塊分析

Nginx源碼解析-
http模塊分析

@author Foyon

創(chuàng)新互聯(lián)長期為上千多家客戶提供的網(wǎng)站建設(shè)服務(wù),團(tuán)隊從業(yè)經(jīng)驗10年,關(guān)注不同地域、不同群體,并針對不同對象提供差異化的產(chǎn)品和服務(wù);打造開放共贏平臺,與合作伙伴共同營造健康的互聯(lián)網(wǎng)生態(tài)環(huán)境。為武川企業(yè)提供專業(yè)的成都做網(wǎng)站、網(wǎng)站制作,武川網(wǎng)站改版等技術(shù)服務(wù)。擁有十多年豐富建站經(jīng)驗和眾多成功案例,為您定制開發(fā)。1.Http模塊整體工作原理

二、event模塊工作原理

三、HTTP框架初始化

斷點看源碼
gdb->
->file /data/home/fanhy/soft/nginx_debug/nginx/sbin/nginx
->b ngx_http_block
->r
->p *cf
->p *cmd
->p *cf->conf_file->buffer

###############################################################

(gdb) file /data/home/fanhy/soft/nginx_debug/nginx/sbin/nginx

Reading symbols from /data/home/fanhy/soft/nginx_debug/nginx/sbin/nginx...done.

(gdb) b ngx_http_block

Breakpoint 1 at 0x43b0a6: file src/http/ngx_http.c, line 121.

(gdb) info b

Num Type Disp Enb Address What

1 breakpoint keep y 0x000000000043b0a6 in ngx_http_block at src/http/ngx_http.c:121

(gdb) r

Starting program: /data/home/fanhy/soft/nginx_debug/nginx/sbin/nginx

[Thread debugging using libthread_db enabled]

Breakpoint 1, ngx_http_block (cf=0x7fffffffe270, cmd=0x71db80, conf=0x760a38) at src/http/ngx_http.c:121

121 {

Missing separate debuginfos, use: debuginfo-install glibc-2.12-1.107.el6.x86_64 keyutils-libs-1.4-4.el6.x86_64 krb5-libs-1.10.3-10.el6_4.1.x86_64 libcom_err-1.41.12-14.el6_4.2.x86_64 libselinux-2.0.94-5.3.el6.x86_64 nss-softokn-freebl-3.12.9-11.el6.x86_64 openssl-1.0.0-27.el6_4.2.x86_64 pcre-7.8-6.el6.x86_64 zlib-1.2.3-29.el6.x86_64

(gdb) n

133 ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_conf_ctx_t));

(gdb) n

134 if (ctx == NULL) {

(gdb) n

138(ngx_http_conf_ctx_t *) conf = ctx;

(gdb) p *cf

$1 = {name = 0x0, args = 0x760db8, cycle = 0x75fc30, pool = 0x75fbe0, temp_pool = 0x763bf0, conf_file = 0x7fffffffdf80, log = 0x730960, ctx = 0x7609f8,

module_type = 1163022147, cmd_type = 16777216, handler = 0, handler_conf = 0x0}

(gdb) p *cf->conf_file->buffer ############加載配置

$2 = {

pos = 0x767d54 "n include mime.types;n default_type application/octet-stream;nn #log_format main \'$remote_addr - $remote_user [$time_local] "$request" \'n #", \' \' <repeats 18 times>, "\'$status $body_bytes_s"..., last = 0x76888e "", file_pos = 16384, file_last = 221589780121,

start = 0x767c00 "user fanhy;nworker_processes 1;nnerror_log logs/nginxdubug_error.log debug_http;n#error_log logs/nginxdubug_error.log debug_core;n#error_log logs/nginxdubug_error.log debug_http;nn#error_log log"..., end = 0x768c00 "", tag = 0x0, file = 0x419335, shadow = 0x0, temporary = 1, memory = 0,

mmap = 0, recycled = 0, in_file = 1, flush = 1, sync = 1, last_buf = 1, last_in_chain = 1, last_shadow = 1, temp_file = 0, num = 0}


http框架初始化,配置文件解析


HTTP框架執(zhí)行流程

對于nginx來說,一個請求是從ngx_http_init_request開始的。 解析請求行

ngx_http_init_request這個函數(shù)中,會設(shè)置讀事件為ngx_http_process_request_line,也就是說,接下來的網(wǎng)絡(luò)事件,會由ngx_http_process_request_line來執(zhí)行。從ngx_http_process_request_line的函數(shù)名,我們可以看到,這就是來處理請求行的,正好與之前講的,處理請求的第一件事就是處理請求行是一致的。通過ngx_http_read_request_header來讀取請求數(shù)據(jù)。然后調(diào)用ngx_http_parse_request_line函數(shù)來解析請求行。

nginx為提高效率,采用狀態(tài)機(jī)來解析請求行,而且在進(jìn)行method的比較時,沒有直接使用字符串比較,而是將四個字符轉(zhuǎn)換成一個整形,然后一次比較以減少cpu的指令數(shù),這個前面有說過。很多人可能很清楚一個請求行包含請求的方法,uri,版本,卻不知道其實在請求行中,也是可以包含有host的。比如一個請求GEThttp://www.taobao.com/uriHTTP/1.0這樣一個請求行也是合法的,而且host是www.taobao.com,這個時候,nginx會忽略請求頭中的host域,而以請求行中的這個為準(zhǔn)來查找虛擬主機(jī)。另外,對于對于http0.9版來說,是不支持請求頭的,所以這里也是要特別的處理。所以,在后面解析請求頭時,協(xié)議版本都是1.0或1.1。整個請求行解析到的參數(shù),會保存到ngx_http_request_t結(jié)構(gòu)當(dāng)中。

解析請求頭

在解析完請求行后,nginx會設(shè)置讀事件的handler為ngx_http_process_request_headers,然后后續(xù)的請求就在ngx_http_process_request_headers中進(jìn)行讀取與解析。ngx_http_process_request_headers函數(shù)用來讀取請求頭,跟請求行一樣,還是調(diào)用ngx_http_read_request_header來讀取請求頭,調(diào)用ngx_http_parse_header_line來解析一行請求頭,解析到的請求頭會保存到ngx_http_request_t的域headers_in中,headers_in是一個鏈表結(jié)構(gòu),保存所有的請求頭。而HTTP中有些請求是需要特別處理的,這些請求頭與請求處理函數(shù)存放在一個映射表里面,即ngx_http_headers_in,在初始化時,會生成一個hash表,當(dāng)每解析到一個請求頭后,就會先在這個hash表中查找,如果有找到,則調(diào)用相應(yīng)的處理函數(shù)來處理這個請求頭。比如:Host頭的處理函數(shù)是ngx_http_process_host。

處理請求

當(dāng)nginx解析到兩個回車換行符時,就表示請求頭的結(jié)束,此時就會調(diào)用ngx_http_process_request來處理請求了。

ngx_http_process_request會設(shè)置當(dāng)前的連接的讀寫事件處理函數(shù)為ngx_http_request_handler,然后再調(diào)用ngx_http_handler來真正開始處理一個完整的http請求。這里可能比較奇怪,讀寫事件處理函數(shù)都是ngx_http_request_handler,其實在這個函數(shù)中,會根據(jù)當(dāng)前事件是讀事件還是寫事件,分別調(diào)用ngx_http_request_t中的read_event_handler或者是write_event_handler。由于此時,我們的請求頭已經(jīng)讀取完成了,之前有說過,nginx的做法是先不讀取請求body,所以這里面我們設(shè)置read_event_handler為ngx_http_block_reading,即不讀取數(shù)據(jù)了。剛才說到,真正開始處理數(shù)據(jù),是在ngx_http_handler這個函數(shù)里面,這個函數(shù)會設(shè)置write_event_handler為ngx_http_core_run_phases,并執(zhí)行ngx_http_core_run_phases函數(shù)。

ngx_http_core_run_phases這個函數(shù)將執(zhí)行多階段請求處理,nginx將一個http請求的處理分為多個階段,那么這個函數(shù)就是執(zhí)行這些階段來產(chǎn)生數(shù)據(jù)。因為ngx_http_core_run_phases最后會產(chǎn)生數(shù)據(jù),所以我們就很容易理解,為什么設(shè)置寫事件的處理函數(shù)為ngx_http_core_run_phases了。

在這里,我簡要說明了一下函數(shù)的調(diào)用邏輯,我們需要明白最終是調(diào)用ngx_http_core_run_phases來處理請求,產(chǎn)生的響應(yīng)頭會放在ngx_http_request_t的headers_out中,這一部分內(nèi)容,我會放在請求處理流程里面去講。

nginx的各種階段會對請求進(jìn)行處理,最后會調(diào)用filter來過濾數(shù)據(jù),對數(shù)據(jù)進(jìn)行加工,如truncked傳輸、gzip壓縮等。這里的filter包括headerfilter與body filter,即對響應(yīng)頭或響應(yīng)體進(jìn)行處理。filter是一個鏈表結(jié)構(gòu),分別有header filter與body filter,先執(zhí)行header filter中的所有filter,然后再執(zhí)行body filter中的所有filter。在header filter中的最后一個filter,即ngx_http_header_filter,這個filter將會遍歷所的有響應(yīng)頭,最后需要輸出的響應(yīng)頭的一個連續(xù)的內(nèi)存,然后調(diào)用ngx_http_write_filter進(jìn)行輸出。ngx_http_write_filter是body filter中的最后一個,所以nginx首先的body信息,在經(jīng)過一系列的body filter之后,最后也會調(diào)用ngx_http_write_filter來進(jìn)行輸出。

這里要注意的是,nginx會將整個請求頭都放在一個buffer里面,這個buffer的大小通過配置項client_header_buffer_size來設(shè)置,如果用戶的請求頭太大,這個buffer裝不下,那nginx就會重新分配一個新的更大的buffer來裝請求頭,這個大buffer可以通過large_client_header_buffers來設(shè)置,這個large_buffer這一組buffer,比如配置4 8k,就是表示有四個8k大小的buffer可以用。注意,為了保存請求行或請求頭的完整性,一個完整的請求行或請求頭,需要放在一個連續(xù)的內(nèi)存里面,所以,一個完整的請求行或請求頭,只會保存在一個buffer里面。這樣,如果請求行大于一個buffer的大小,就會返回414錯誤,如果一個請求頭大小大于一個buffer大小,就會返回400錯誤。在了解了這些參數(shù)的值,以及nginx實際的做法之后,在應(yīng)用場景,我們就需要根據(jù)實際的需求來調(diào)整這些參數(shù),來優(yōu)化我們的程序了。

文章標(biāo)題:Nginx源碼解析-http模塊分析
路徑分享:http://www.rwnh.cn/article4/cjopoe.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供Google、響應(yīng)式網(wǎng)站網(wǎng)站設(shè)計、微信小程序動態(tài)網(wǎng)站、網(wǎng)站策劃

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)

小程序開發(fā)
蚌埠市| 高陵县| 新田县| 沅陵县| 申扎县| 岑溪市| 永春县| 新源县| 甘德县| 灵武市| 明水县| 台中县| 南丰县| 会东县| 彰化市| 双辽市| 江山市| 广灵县| 中牟县| 增城市| 宁晋县| 东乡| 全州县| 安顺市| 徐汇区| 资阳市| 垫江县| 义马市| 泽州县| 清原| 留坝县| 通许县| 福建省| 枝江市| 五常市| 镶黄旗| 定安县| 昌乐县| 宿松县| 夹江县| 乌鲁木齐市|