來(lái)源:碼農(nóng)桃花源 上一篇文章《三次握手,四次揮手”你真的懂嗎?》中,我們學(xué)會(huì)了用wireshark和tcpdump來(lái)分析TCP的“三次握手,四次揮手”,非常好用。這哥倆就是傳說(shuō)中的 為了對(duì)網(wǎng)絡(luò)數(shù)據(jù)包的“流轉(zhuǎn)”有更加深刻的理解,我在docker(遠(yuǎn)程)上部署一個(gè)服務(wù),支持http方式調(diào)用。從客戶端(本地)用http方式請(qǐng)求其中的一個(gè)接口,并得到響應(yīng)數(shù)據(jù)。同時(shí)本地通過(guò)wireshark抓包,遠(yuǎn)程用tcpdump抓包,然后分析過(guò)程中的所有通信細(xì)節(jié)。悲劇是把美好的東西撕碎給人看,而我則是把復(fù)雜的東西撕碎了給人看。 文章稍長(zhǎng),請(qǐng)?jiān)诳幢疚臅r(shí)保持耐心。我先通過(guò)工具獲取HTTP通信的數(shù)據(jù)包,再來(lái)抽絲剝繭,深入二進(jìn)制的天地里,解密HTTP所有的通信細(xì)節(jié)。分析過(guò)程中,由點(diǎn)到面,將相關(guān)知識(shí)串接起來(lái)。保證全篇讀完之后,你對(duì)HTTP的理解會(huì)上升一個(gè)臺(tái)階! 為了更好的閱讀體驗(yàn),我手動(dòng)貼上本文的目錄: HTTP報(bào)文截獲背景介紹我手頭現(xiàn)在有一個(gè)地理幾何相關(guān)的服務(wù),它提供一組接口對(duì)外使用。其中有一個(gè)接口是 我請(qǐng)求服務(wù)的“Fence2Area”接口,輸入圍欄(fence)頂點(diǎn)(lng, lat)坐標(biāo)、坐標(biāo)系類型(coordtype),輸出的則是多邊形的面積(area). 一次正常的請(qǐng)求示例url, 這個(gè)大家都不陌生(我用docker_ip代替真實(shí)的ip):
請(qǐng)求發(fā)出后,服務(wù)器進(jìn)行處理,之后,客戶端收到返回的數(shù)據(jù)如下:
抓包在真正發(fā)送請(qǐng)求之前,需要進(jìn)行抓包前的設(shè)置。在本地mac,我用wireshark; 而在遠(yuǎn)程docker上,我用tcpdump工具。 mac本地設(shè)置wireshark包過(guò)濾器,監(jiān)控本地主機(jī)和遠(yuǎn)程docker之間的通信。
點(diǎn)擊開(kāi)始捕獲。 遠(yuǎn)程docker該服務(wù)通過(guò)7080端口對(duì)外提供,使用如下命令捕獲網(wǎng)絡(luò)包:
請(qǐng)求 && 分析準(zhǔn)備工作做完,我選了一個(gè)神圣的時(shí)刻,在本地通過(guò)瀏覽器訪問(wèn)如下url:
這樣本地的wireshark和遠(yuǎn)程的tcpdump都能抓取到HTTP網(wǎng)絡(luò)數(shù)據(jù)包。 關(guān)閉服務(wù)進(jìn)程正式請(qǐng)求之前,我們先看一下幾種特殊的情形。 首先,關(guān)閉gcs服務(wù)進(jìn)程,請(qǐng)求直接返回RST報(bào)文。 如上圖,我在請(qǐng)求的時(shí)候,訪問(wèn)服務(wù)端的另一個(gè)端口 關(guān)閉docker關(guān)閉docker, 由于發(fā)送的SYN報(bào)文段得不到響應(yīng),因此會(huì)進(jìn)行重試,mac下重試的次數(shù)為10次。 先每隔1秒重試了5次,再用“指數(shù)退避”的時(shí)間間隔重試,2s, 4s, 8s, 16s, 32s. 最后結(jié)束。 重啟docker先進(jìn)行一次正常的訪問(wèn),隨后重啟docker。并再次在本地訪問(wèn)以上url, 瀏覽器這時(shí)還是用的上一次的端口,訪問(wèn)到服務(wù)端后,因?yàn)樗呀?jīng)重啟了,所以服務(wù)端已經(jīng)沒(méi)有這個(gè)連接的消息了。因此會(huì)返回一個(gè)RST報(bào)文。 正常請(qǐng)求服務(wù)正常啟動(dòng),正常發(fā)送請(qǐng)求,這次請(qǐng)求成功,那是當(dāng)然的,嘿嘿! 這是在mac上用wireshark捕獲的數(shù)據(jù)包,共7個(gè)包,前三個(gè)包為3次握手的包,第四個(gè)包為 重點(diǎn)來(lái)關(guān)注后面幾個(gè)包,先看第四個(gè)包,
我們來(lái)逐字節(jié)分析。 剩余的數(shù)據(jù)部分即為T(mén)CP協(xié)議相關(guān)的。TCP也是20B固定長(zhǎng)度 可變長(zhǎng)度部分。 可變長(zhǎng)度部分,協(xié)議如下: 剩下來(lái)的就是數(shù)據(jù)部分了。我們一行一行地看。因?yàn)閔ttp是字符流,所以我們先看一下ascii字符集,執(zhí)行命令:
可以得到ascii碼,我們直接看十六進(jìn)制的結(jié)果: 把上表的最后一列連起來(lái),就是:
其中,cr nl表示回車(chē),換行。 docker收到數(shù)據(jù)后,會(huì)回復(fù)一個(gè)ack包。第四個(gè)包的總長(zhǎng)度為661字節(jié),去掉IP頭部20字節(jié),TCP頭部固定部分20字節(jié),TCP頭部可選長(zhǎng)度為12字節(jié),共52字節(jié),因此TCP數(shù)據(jù)部分總長(zhǎng)度為661-52=609字節(jié)。另外,序列號(hào)為2778351310. 再來(lái)看第5個(gè)包,字節(jié)流如下:
剩余的數(shù)據(jù)部分即為T(mén)CP協(xié)議相關(guān)的。TCP也是20B固定長(zhǎng)度 可變長(zhǎng)度部分。 可變長(zhǎng)度部分,協(xié)議如下: 數(shù)據(jù)部分為空,這個(gè)包僅為確認(rèn)包。 再來(lái)看第六個(gè)包,字節(jié)流如下:
剩余的數(shù)據(jù)部分即為T(mén)CP協(xié)議相關(guān)的。TCP也是20B固定長(zhǎng)度 可變長(zhǎng)度部分。 可變長(zhǎng)度部分,協(xié)議如下: 剩下來(lái)的就是數(shù)據(jù)部分了。我們一行一行地看。 把上表的最后一列連起來(lái),就是:
Content-Length: 48,最后一行的長(zhǎng)度即為48個(gè)字節(jié)。 最后,第七個(gè)包,字節(jié)流如下:
剩余的數(shù)據(jù)部分即為T(mén)CP協(xié)議相關(guān)的。TCP也是20B固定長(zhǎng)度 可變長(zhǎng)度部分。 可變長(zhǎng)度部分,協(xié)議如下: 至此,一次完整的http請(qǐng)求的報(bào)文就解析完了。感覺(jué)如何,是不是很親切? HTTP協(xié)議分析上面我們把HTTP協(xié)議相關(guān)的數(shù)據(jù)給解構(gòu)了,下面我將對(duì)照上面的數(shù)據(jù)拆解結(jié)果,一步步帶你深入理解HTTP協(xié)議。 整體介紹
HTTP屬于應(yīng)用層協(xié)議,底層是靠TCP進(jìn)行可靠地信息傳輸。 HTTP在傳輸一段報(bào)文時(shí),會(huì)以 編碼我們?cè)賮?lái)回顧一下: 原始的url值:
編碼后的url值:
在之前的報(bào)文拆解過(guò)程中,我們看到多了很多 一方面,URL描述的資源為了能通過(guò)其他各種協(xié)議傳送,但是有些協(xié)議在傳輸過(guò)程中會(huì)剝?nèi)ヒ恍┨囟ǖ淖址涣硪环矫?,URL還是可讀的,所以那些不可打印的字符就不能在URL中使用了,比如空格;最后,URL還得是完整的,它需要支持所有語(yǔ)言的字符。 總之,基于很多原因,URL設(shè)計(jì)者將US-ASCII碼和其轉(zhuǎn)義序列集成到URL中,通過(guò)轉(zhuǎn)義序列,就可以用US-ASCII字符集的有限子集對(duì)任意字符或數(shù)據(jù)進(jìn)行編碼了。 轉(zhuǎn)義的方法:百分號(hào)( 所以上面在瀏覽器發(fā)送給服務(wù)器的URL進(jìn)行了非“安全字符”編碼,也就不奇怪了吧? 在URL中,當(dāng)上面的保留字符用在保留用途之外的場(chǎng)合時(shí),需要對(duì)URL進(jìn)行編碼。 MIME類型響應(yīng)數(shù)據(jù)中,我們注意到有一個(gè)首部:
互聯(lián)網(wǎng)上有數(shù)千種不同的數(shù)據(jù)類型,HTTP給每種對(duì)象都打上了MIME(Multipurpose Internet Media Extension, 多用途因特網(wǎng)郵件擴(kuò)展)標(biāo)簽,也就是響應(yīng)數(shù)據(jù)中的 URI/URL/URN URI(Uniform Resource Identifier, 統(tǒng)一資源標(biāo)識(shí)符)表示服務(wù)器資源,URL(Uniform Resource Locator, 統(tǒng)一資源定位符)和URN(Uniform Resource Name, 統(tǒng)一資源名)是URI的具體實(shí)現(xiàn)。URI是一個(gè)通用的概念,由兩個(gè)主要的子集URL和URN構(gòu)成,URL通過(guò)位置、URN通過(guò)名字來(lái)標(biāo)識(shí)資源。 URL定義了資源的位置,表示資源的實(shí)際地址,在使用URL的過(guò)程中,如果URL背后的資源發(fā)生了位置移動(dòng),訪問(wèn)者就找不到它了。這個(gè)時(shí)候就要用到URN了,它給定資源一個(gè)名字,無(wú)論它移動(dòng)到哪里,都可以通過(guò)這個(gè)名字來(lái)訪問(wèn)到它,簡(jiǎn)直完美! URL通常的格式是:
協(xié)議方案(scheme),如 HTTP方法HTTP支持幾種不同的請(qǐng)求方法,每種方法對(duì)服務(wù)器要求的動(dòng)作不同,如下圖是幾種常見(jiàn)的方法: HEAD方法只獲取頭部,不獲取數(shù)據(jù)部分。通過(guò)頭部可以獲取比如資源的類型(Content-Type)、資源的長(zhǎng)度(Content-Length)這些信息。這樣,客戶端可以獲取即將請(qǐng)求資源的一些情況,可以做到心中有數(shù)。 POST用于向服務(wù)器發(fā)送數(shù)據(jù),常見(jiàn)的是提交表單;PUT用于向服務(wù)器上的資源存儲(chǔ)數(shù)據(jù)。 狀態(tài)碼每條HTTP的響應(yīng)報(bào)文都會(huì)帶上一個(gè)三位數(shù)字的狀態(tài)碼和一條解釋性的“原因短語(yǔ)”,通知客戶端本次請(qǐng)求的狀態(tài),幫助客戶端快速理解事務(wù)處理結(jié)果,最常見(jiàn)的是:
我們平時(shí)使用瀏覽器的時(shí)候,很多的錯(cuò)誤碼其實(shí)是由瀏覽器處理的,我們感知不到。但是 客戶端可以據(jù)此狀態(tài)碼,決定下一步的行動(dòng)(如重定向等)。 三位數(shù)字的第一位表示分類: 報(bào)文格式HTTP報(bào)文實(shí)際上是由一行行的字符串組成的,每行字符串的末尾用 舉個(gè)簡(jiǎn)單的請(qǐng)求報(bào)文和響應(yīng)報(bào)文的格式的例子: 實(shí)際上,請(qǐng)求報(bào)文也是可以有body(主體)部分的。請(qǐng)求報(bào)文是由 響應(yīng)報(bào)文的格式和請(qǐng)求報(bào)文的格式類似: 請(qǐng)求報(bào)文、響應(yīng)報(bào)文的起始行和響應(yīng)頭部里的字段都是文本化、結(jié)構(gòu)化的。而請(qǐng)求body卻可以包含任意二進(jìn)制數(shù)據(jù)(如圖片、視頻、軟件等),當(dāng)然也可以包含文本。 有些首部是通用的,有些則是請(qǐng)求或者響應(yīng)報(bào)文才會(huì)有的。 順便提一下, 用telnet直連服務(wù)器的http端口,telnet命令會(huì)建立一條TCP通道,然后就可以通過(guò)這個(gè)通道直接發(fā)送HTTP請(qǐng)求數(shù)據(jù),獲取響應(yīng)數(shù)據(jù)了。 HTTP協(xié)議進(jìn)階代理HTTP的代理服務(wù)器既是Web服務(wù)器,又是Web客戶端。 使用代理可以“接觸”到所有流過(guò)的HTTP流量,代理可以對(duì)其進(jìn)行監(jiān)視和修改。常見(jiàn)的就是對(duì)兒童過(guò)濾一些“成人”內(nèi)容;網(wǎng)絡(luò)工程師會(huì)利用代理服務(wù)器來(lái)提高安全性,它可以限制哪些應(yīng)用層的協(xié)議數(shù)據(jù)可以通過(guò),過(guò)濾“病毒”等數(shù)據(jù);代理可以存儲(chǔ)緩存的文件,直接返回給訪問(wèn)者,無(wú)需請(qǐng)求原始的服務(wù)器資源;對(duì)于訪問(wèn)慢速網(wǎng)絡(luò)上的公共內(nèi)容時(shí),可以假扮服務(wù)器提供服務(wù),從而提高訪問(wèn)速度;這被稱為 現(xiàn)實(shí)中,請(qǐng)求通過(guò)以下幾種方式打到代理服務(wù)器上去: 報(bào)文每經(jīng)過(guò)一個(gè)中間點(diǎn)(代理或網(wǎng)關(guān)),都需要在首部via字段的末尾插入一個(gè)可以代表本節(jié)點(diǎn)的獨(dú)特的字符串,包含實(shí)現(xiàn)的協(xié)議版本和主機(jī)地址。注意圖中的via字段。 請(qǐng)求和響應(yīng)的報(bào)文傳輸路徑通常都是一致的,只不過(guò)方向是相反的。因此,響應(yīng)報(bào)文上的via字段表示的中間節(jié)點(diǎn)的順序是剛好相反的。 緩存當(dāng)有很多請(qǐng)求訪問(wèn)同一個(gè)頁(yè)面時(shí),服務(wù)器會(huì)多次傳輸同一份數(shù)據(jù),這些數(shù)據(jù)重復(fù)地在網(wǎng)絡(luò)中傳輸著,消耗著大量帶寬。如果將這些數(shù)據(jù)緩存下來(lái),就可以提高響應(yīng)速度,節(jié)省網(wǎng)絡(luò)帶寬了。 大部分緩存只有在客戶端發(fā)起請(qǐng)求,并且副本已經(jīng)比較舊的情況下才會(huì)對(duì)副本的新鮮度進(jìn)行檢測(cè)。最常用的請(qǐng)求首部是 再驗(yàn)證可能出現(xiàn)命中或未命中的情況。未命中時(shí),服務(wù)器回復(fù) 順帶提一句,若要在項(xiàng)目中使用緩存,就一定要關(guān)注緩存命中比例。若命中比例不高,就要重新考慮設(shè)置緩存的必要性了。 緩存服務(wù)器返回響應(yīng)的時(shí)候,是基于已緩存的服務(wù)器響應(yīng)的首部,再對(duì)一些首部字段做一些微調(diào)。比如向其中插入新鮮度信息(如 HTTP通過(guò) 文檔過(guò)期通過(guò)如下首部字段來(lái)表示緩存的有效期: 當(dāng)上面兩個(gè)字段暗示的過(guò)期時(shí)間已到,需要向服務(wù)器再次驗(yàn)證文檔的新鮮度。如果這時(shí)緩存仍和服務(wù)器上的原始文檔一致,緩存只需要更新頭部的相關(guān)字段。如上表中提到的 為了更好的節(jié)省網(wǎng)絡(luò)流量,緩存服務(wù)器可以通過(guò)相關(guān)首部向原始服務(wù)器發(fā)送一個(gè) cookiecookie是服務(wù)器“貼在”客戶端身上的標(biāo)簽,由客戶端維護(hù)的狀態(tài)片段,并且只會(huì)回送給合適的站點(diǎn)。 有兩類cookie: 會(huì)話cookie、持久cookie. 會(huì)話cookie在退出瀏覽器后就被刪除了;而持久cookie則保存在硬盤(pán)中,計(jì)算機(jī)重啟后仍然存在。 服務(wù)器在給客戶端的響應(yīng)字段首部加上 瀏覽器只會(huì)向產(chǎn)生這條cookie的站點(diǎn)發(fā)生cookie.
那么瀏覽器在訪問(wèn)任意以
實(shí)體和編碼響應(yīng)報(bào)文中的body部分傳輸?shù)臄?shù)據(jù)本質(zhì)上都是二進(jìn)制。我們從上面的報(bào)文數(shù)據(jù)也可以看出來(lái),都是用十六進(jìn)制數(shù)來(lái)表示,關(guān)鍵是怎么解釋這塊內(nèi)容。如果
HTTP的早期版本采用關(guān)閉連接的方式來(lái)劃定報(bào)文的結(jié)束。這帶來(lái)的問(wèn)題是顯而易見(jiàn)的:客戶端并不能分清是因?yàn)榉?wù)器正常結(jié)束還是中途崩潰了。這里,如果是客戶端用關(guān)閉來(lái)表示請(qǐng)求報(bào)文主體部分的結(jié)束,是不可取的,因?yàn)殛P(guān)閉之后,就無(wú)法獲取服務(wù)器的響應(yīng)了。當(dāng)然,客戶端可以采用半關(guān)閉的方式,只關(guān)閉數(shù)據(jù)發(fā)送方向,但是很多服務(wù)器是不識(shí)別的,會(huì)把半關(guān)閉當(dāng)成客戶端要成服務(wù)器斷開(kāi)來(lái)處理。 HTTP報(bào)文在傳輸?shù)倪^(guò)程中可能會(huì)遭到代理或是其他通信實(shí)體的無(wú)意修改,為了讓接收方知道這種情況,服務(wù)器會(huì)對(duì)body部分作一個(gè)md5, 并把值放到 HTTP在發(fā)送內(nèi)容之前需要對(duì)其進(jìn)行編碼,它是對(duì)報(bào)文主體進(jìn)行的可逆變換。比如將報(bào)文用gzip格式進(jìn)行壓縮,減少傳輸時(shí)間。常見(jiàn)的編碼類型如下: 當(dāng)然,客戶端為了避免服務(wù)器返回自己不能解碼的數(shù)據(jù),請(qǐng)求的時(shí)候,會(huì)在 上面提到的編碼是內(nèi)容編碼,它只是在響應(yīng)報(bào)文的主體報(bào)文將原始數(shù)據(jù)進(jìn)行編碼,改變的是內(nèi)容的格式。還有另一種編碼: 通常,服務(wù)器需要先生成數(shù)據(jù),再進(jìn)行傳輸,這時(shí),可以計(jì)算數(shù)據(jù)的長(zhǎng)度,并將其編碼到 HTTP協(xié)議中通過(guò)如下兩個(gè)首部來(lái)描述和控制傳輸編碼: 分塊編碼的報(bào)文形式是這樣的: 每個(gè)分塊包含一個(gè)長(zhǎng)度值(十六進(jìn)制,字節(jié)數(shù))和該分塊的數(shù)據(jù)。 內(nèi)容編碼和傳輸編碼是可以結(jié)合起來(lái)使用的。 國(guó)際化支持HTTP為了支持國(guó)際化的內(nèi)容,客戶端要告知服務(wù)器自己能理解的何種語(yǔ)言,以及瀏覽器上安裝了何種字母表編碼算法。這通過(guò) 比如:
表示:客戶端接受法語(yǔ)(fr, 優(yōu)先級(jí)默認(rèn)為1.0)、英語(yǔ)(en, 優(yōu)先級(jí)為0.8),支持iso-8859-1, utf-8兩種字符集編碼。服務(wù)器則會(huì)在 本質(zhì)上,HTTP報(bào)文的body部分存放的就是一串二進(jìn)制碼,我們先把二進(jìn)制碼轉(zhuǎn)換成字符代碼(如ascii是一個(gè)字節(jié)表示一個(gè)字符,而utf-8則表示一個(gè)字符的字節(jié)數(shù)不定,每個(gè)字符1~6個(gè)字節(jié)),之后,用字符代碼去字符集中找到對(duì)應(yīng)的元素。 比較常見(jiàn)的字符集是
舉個(gè)例子,漢字“嚴(yán)”的Unicode編碼為
重定向與負(fù)載均衡Web內(nèi)容通常分散地分布在很多地方,這可以防止“單點(diǎn)故障”,萬(wàn)一某個(gè)地方發(fā)生地震了,機(jī)房被毀了,那還有其他地方的機(jī)房可以提供服務(wù)。一般都會(huì)有所謂的“雙活”,“多活”,所謂 這樣,用戶的請(qǐng)求會(huì)根據(jù) HTTP重定向服務(wù)器收到客戶端請(qǐng)求后,向客戶端返回一條帶有狀態(tài)碼 當(dāng)然,缺點(diǎn)也是顯而易見(jiàn)的,由于客戶端要發(fā)送兩次請(qǐng)求,因此會(huì)增加耗時(shí)。 DNS重定向DNS將幾個(gè)IP地址關(guān)聯(lián)到一個(gè)域上,采用算法決定返回的IP地址??梢允呛?jiǎn)單的 DNS服務(wù)器總是會(huì)返回所有的IP地址,但是DNS客戶端一般只會(huì)使用第一個(gè)IP地址,而且會(huì)緩存下來(lái),之后會(huì)一直用這個(gè)地址。所以,DNS輪轉(zhuǎn)通常不會(huì)平衡單個(gè)客戶端的負(fù)載。但是,由于DNS服務(wù)器對(duì)于不同的請(qǐng)求,總是會(huì)返回輪轉(zhuǎn)后的IP地址列表,因此,會(huì)把負(fù)載分散到多個(gè)客戶端。 HTTP連接HTTP連接是HTTP報(bào)文傳輸?shù)年P(guān)鍵通道。 并行連接對(duì)于一個(gè)頁(yè)面上同時(shí)出現(xiàn)多個(gè)對(duì)象的時(shí)候,如果瀏覽器并行地打開(kāi)多個(gè)連接,同時(shí)去獲取這些對(duì)象,多個(gè)連接的TCP握手時(shí)延可以進(jìn)行重疊,速度會(huì)快起來(lái)。 如一個(gè)包含3張圖片的頁(yè)面,瀏覽器要發(fā)送4次HTTP請(qǐng)求來(lái)獲取頁(yè)面。1個(gè)用于頂層的HTML頁(yè)面,3個(gè)用于圖片。如果采用串行方式,那么連接時(shí)延會(huì)進(jìn)行疊加。 采用并行連接之后: 但是并行連接也不絕對(duì)提升速度,如果一個(gè)頁(yè)面有數(shù)百個(gè)內(nèi)嵌對(duì)象,那要啟動(dòng)數(shù)百個(gè)連接,對(duì)服務(wù)器的性能也是非常大的挑戰(zhàn)。所以,通常瀏覽器會(huì)限制并行連接的總數(shù)據(jù)在一個(gè)較小的值,通常是4個(gè),而且服務(wù)端可以隨意關(guān)閉客戶端超量的連接。 另一方面,如果客戶端網(wǎng)絡(luò)帶寬較小,每個(gè)連接都會(huì)去爭(zhēng)搶有限的帶寬,每個(gè)連接都會(huì)獲取較小的速度,即每個(gè)對(duì)象都會(huì)以較小的速度去加載。這樣,并行連接帶來(lái)的速度提升就會(huì)比較小,甚至沒(méi)有提升。 持久連接HTTP keep-alive機(jī)制 我們知道HTTP請(qǐng)求是“請(qǐng)求-應(yīng)答”模式,每次請(qǐng)求-應(yīng)答都要新建一個(gè)連接,完成之后要斷開(kāi)連接。HTTP是無(wú)狀態(tài)的,連接之間沒(méi)有任何關(guān)系。 HTTP是應(yīng)用層協(xié)議,TCP是傳輸層協(xié)議。HTTP底層仍然采用TCP進(jìn)行傳輸數(shù)據(jù)。TCP為HTTP提供了一層可靠的比特傳輸通道。HTTP一般交換的數(shù)據(jù)都不大,而每次連接都要進(jìn)行TCP三次握手,很大一部分時(shí)間都消耗在這上面,有時(shí)候甚至能達(dá)到50%。如果能復(fù)用連接,就可以減少由于TCP三次握手所帶來(lái)的時(shí)延。 HTTP 1.1默認(rèn)開(kāi)啟keep-alive機(jī)制,從上面抓到的包也可以看到。這樣,數(shù)據(jù)傳輸完成之后保持TCP連接不斷開(kāi),之后同域名下復(fù)用連接,繼續(xù)用這個(gè)通道傳輸數(shù)據(jù)。服務(wù)器在響應(yīng)一個(gè)請(qǐng)求后,可以保持這個(gè)連接keep-alive timeout的時(shí)間,在這個(gè)時(shí)間內(nèi)沒(méi)有請(qǐng)求,則關(guān)閉此連接;否則,重新開(kāi)始倒計(jì)時(shí)keep-alive timeout時(shí)間。 HTTP有keep-alive機(jī)制,目的是可以在一個(gè)TCP 連接上傳輸多個(gè)HTTP事務(wù),以此提高通信效率。底層的TCP其實(shí)也有keep-alive機(jī)制,它是為了探測(cè)TCP連接的活躍性。TCP層的keepalive可以在任何一方設(shè)置,可以是一端設(shè)置、兩端同時(shí)設(shè)置或者兩端都沒(méi)有設(shè)置。新建socket的時(shí)候需要設(shè)置,從而使得協(xié)議棧調(diào)用相關(guān)函數(shù)tcpsetkeepalive,來(lái)激活連接的keep-alive屬性。 當(dāng)網(wǎng)絡(luò)兩端建立了TCP連接之后,閑置(雙方?jīng)]有任何數(shù)據(jù)流發(fā)送往來(lái))時(shí)間超過(guò) 管道化連接在keep-alive的基礎(chǔ)上,我們可以做地更進(jìn)一步,在響應(yīng)到達(dá)之前,我們將多條請(qǐng)求按序放入請(qǐng)求隊(duì)列,服務(wù)端在收到請(qǐng)求后,必須按照順序?qū)?yīng)請(qǐng)求的響應(yīng)。但由于網(wǎng)絡(luò)環(huán)境非常復(fù)雜,因此即使請(qǐng)求是按順序發(fā)送的,也不一定是按順序到達(dá)服務(wù)端的。而且就算是服務(wù)端按序處理的,也不一定是按序返回給客戶端,所以最好是在響應(yīng)中附帶一些可以標(biāo)識(shí)請(qǐng)求的參數(shù)。 為了安全起見(jiàn),管道化的連接只適合“冪等”的請(qǐng)求,一般我們認(rèn)為:GET/HEAD/PUT/DELETE/TRACE/OPTIONS等方法都是冪等的。 小結(jié)以上,就是所有HTTP的通信細(xì)節(jié)了,足夠在日常開(kāi)發(fā) 作中使用了。更多沒(méi)有涉及的細(xì)節(jié)可以在用到的時(shí)候再去仔細(xì)研究。 文章看完了,不知道你對(duì)HTTP的理解有沒(méi)有更上一層樓?歡迎一起交流探討。 參考資料【http長(zhǎng)連接】https://www.cnblogs.com/cswuyg/p/3653263.html 【http/tcp keep alive】https://segmentfault.com/a/1190000012894416 【http/tcp keep alive】http://www./academy/detail/23350305 【http/tcp keep alive】https:///articles/8020/on-the-keep-alive-and-tcp-keep-alive-in-the-http-protocol 【tcp keep alive】http://blog.51cto.com/zxtong/1788252 【http權(quán)威指南】https://book.douban.com/subject/10746113/ 【HTTP狀態(tài)碼】https://www.cnblogs.com/starof/p/5035119.html 【HTTP協(xié)議】https://www.cnblogs.com/ranyonsue/p/5984001.html 【HTTP狀態(tài)分類】http://www.runoob.com/http/http-status-codes.html 【url編碼】http://www./blog/2010/02/url_encoding.html |
|
來(lái)自: liang1234_ > 《http》