<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          一次 HTTP 請(qǐng)求到底經(jīng)歷了什么?

          共 6422字,需瀏覽 13分鐘

           ·

          2021-03-19 12:14

          作者:木木匠

          鏈接:https://url.cn/5ER9kt2

          今天這篇文章我們用抓包分析工具來(lái)分析 HTTP 請(qǐng)求是怎么樣的?

          環(huán)境準(zhǔn)備

          本來(lái)是想找個(gè)網(wǎng)站進(jìn)行抓包分析的,但是正式環(huán)境的網(wǎng)站 HTTP 請(qǐng)求太多,干擾太多,對(duì)分析不太友好,所以簡(jiǎn)單些了一個(gè) demo,對(duì) HTTP 請(qǐng)求返回字符串。

          環(huán)境:

          1. 1.響應(yīng)http請(qǐng)求的服務(wù)demo

          2. 2.客戶端ip:192.168.2.135

          3. 3.服務(wù)端:45.76.105.92

          4. 4.抓包工具:Wireshark

          把 demo部署到服務(wù)器,啟動(dòng)成功訪問(wèn)如下:

          打開(kāi)抓包工具 Wireshark 進(jìn)行抓包,抓包結(jié)果如下:

          從上圖我們已經(jīng)看到成功抓包到一次 HTTP 請(qǐng)求和響應(yīng)了,但是我們看到卻有很多 TCP請(qǐng)求,接下來(lái)我們來(lái)分析下這些 TCP 請(qǐng)求是做什么的?

          抓包分析

          A) 三次握手

          最開(kāi)始是本地發(fā)送了2次請(qǐng)求到服務(wù)器,這里為什么會(huì)有兩次請(qǐng)求,稍后再說(shuō),我們先主要看 HTTP 對(duì)應(yīng)的端口請(qǐng)求,如下:

          1. 192.168.2.135:60738---->45.76.105.92:8081

          看上面的截圖我們知道這是 TCP 協(xié)議的第一次握手,熟悉 TCP 協(xié)議的同學(xué)肯定知道 TCP 建立連接有三次握手,斷開(kāi)連接有四次揮手。

          我們先看第一次請(qǐng)求:

          1. 60738 -> 8081 [SYN] Seq=0 Win=64240 Len=0 Mss=1460 Ws=256 SACK_PERM=1

          我們來(lái)解析下這段包請(qǐng)求信息:

          • 60783->8081 端口號(hào):源端口--->目標(biāo)端口

          • [SYN] :同步握手信號(hào)

          • Seq : 消息編號(hào)

          • Win: TCP 窗口大小

          • Len: 消息長(zhǎng)度

          • Mss: 最大報(bào)文段長(zhǎng)度

          • Ws: 窗口縮放調(diào)整因子

          • SACK_PERM : SACK選項(xiàng),這里等于1表示開(kāi)啟 SACK。

          對(duì)于上面的概念,這里簡(jiǎn)單解釋下,再介紹之前我們先看 TCPHeader 的數(shù)據(jù)結(jié)構(gòu)圖,對(duì) TCP 頭部數(shù)據(jù)結(jié)構(gòu)有個(gè)直觀的了解

          1. Win: TCP 窗口大小,是指 TCP傳輸能接受的最大字節(jié)數(shù),這個(gè)可以進(jìn)行動(dòng)態(tài)調(diào)節(jié),也就是 TCP的滑動(dòng)窗口,通過(guò)動(dòng)態(tài)調(diào)整窗口大小,來(lái)控制發(fā)送數(shù)據(jù)的速率。上圖中占用 2個(gè)字節(jié),也就是 16位,那么可以支持的最大數(shù)就是 2^16=65536,所以默認(rèn)情況下 TCP頭部標(biāo)記能支持的最大窗口數(shù)是 65536字節(jié),也就是 64KB。

          2. Len: 消息長(zhǎng)度 就是指數(shù)據(jù)報(bào)文段,因?yàn)檎麄€(gè) TCP報(bào)文 = Header + packSize,所以這個(gè)消息長(zhǎng)度就是指要傳送的數(shù)據(jù)包總共長(zhǎng)度,在本次分析中也就是 HTTP報(bào)文的大小。

          3. Mss: 最大報(bào)文段長(zhǎng)度:這個(gè)就是規(guī)定最大的能傳輸報(bào)文的長(zhǎng)度,為了達(dá)到最佳的傳輸效能, TCP 協(xié)議在建立連接的時(shí)候通常要協(xié)商雙方的 MSS 值,這個(gè)值 TCP 協(xié)議在實(shí)現(xiàn)的時(shí)候往往用 MTU 值代替(需要減去 IP數(shù)據(jù)包包頭的大小 20Bytes和 TCP數(shù)據(jù)段的包頭 20Bytes)所以一般 MSS 值 1460,這也和我們抓包圖中的值一致。

          4. Ws: 窗口縮放調(diào)整因子:在前面說(shuō) TCP 窗口大小中我們說(shuō)到,默認(rèn)情況下, TCP 窗口大小最大只能支持 64KB的緩沖數(shù)據(jù),在今天這個(gè)高速上網(wǎng)時(shí)代,這個(gè)大小肯定不滿足條件了,所以,為了能夠支持更多的緩沖數(shù)據(jù) RFC 1323中就規(guī)定了 TCP 的擴(kuò)展選項(xiàng),其中窗口縮放調(diào)整因子就是其中之一,這個(gè)是如何起作用的呢?首先說(shuō)明,這個(gè)參數(shù)是在 [SYN] 同步階段進(jìn)行協(xié)商的,我們結(jié)合上面抓包數(shù)據(jù)分析下。我們看到第一次請(qǐng)求協(xié)商的結(jié)果是 WS=256,然后再 ACK 階段擴(kuò)展因子生效,調(diào)整了窗口大小。生效的抓包如下:

          1. 60738 ->8081 [ACK] Seq=1 ACK=1 Win=66560 Len=0

          我們發(fā)現(xiàn)這個(gè)窗口變成了 66560,比默認(rèn)的窗口要大,我們查看報(bào)文詳情:

          我們發(fā)現(xiàn),實(shí)際請(qǐng)求聲明的窗口是 260, WS擴(kuò)展因子是 256,最終計(jì)算的窗口大小是 66560,所以我們知道了,這個(gè)擴(kuò)展因子的作用就是,用原窗口大小乘以擴(kuò)展因子,得到最終的窗口大小,也就是 260*256=66560.

          5. SACK_PERM:SACK選項(xiàng) ,我們知道 TCP 傳輸有包的確認(rèn)機(jī)制,默認(rèn)情況下,接受端接受到一個(gè)包后,發(fā)送 ACK 確認(rèn),但是,默認(rèn)只支持順序的確認(rèn),也就是說(shuō),發(fā)送 ABC 個(gè)包,如果我收到了 AC的包, B沒(méi)有收到,那么對(duì)于 C,這個(gè)包我是不會(huì)確認(rèn)的,需要等 B這個(gè)包收到后再確認(rèn),那么 TCP有超時(shí)重傳機(jī)制,如果一個(gè)包很久沒(méi)有確認(rèn),就會(huì)當(dāng)它丟失了,進(jìn)行重傳,這樣會(huì)造成很多多余的包重傳,浪費(fèi)傳輸空間。為了解決這個(gè)問(wèn)題, SACK就提出了選擇性確認(rèn)機(jī)制,啟用 SACK 后,接受端會(huì)確認(rèn)所有收到的包,這樣發(fā)送端就只用重傳真正丟失的包了。


          簡(jiǎn)單介紹了上面的基礎(chǔ)概念后,我們來(lái)根據(jù)抓包梳理下 HTTP 請(qǐng)求的過(guò)程,根據(jù) HTTP 請(qǐng)求本地端口是 60378,梳理的流程如下:

          1. ------------------------請(qǐng)求連接--------------------------

          2. 1) 60738 -> 8081 [SYN] Seq=0 Win=64240 Len=0 Mss=1460 Ws=256 SACK_PERM=1

          3. 2) 8081 -> 60738 [SYN,ACK] Seq=0 ACK =1 Win=29200 Len=0 MSS=1420 SACK_PERM=1 WS=128

          4. 3) 60738 -> 8081 [ACK] Seq=1 ACK=1 Win=66560 Len=0

          5. 4) Get /test HTTP/1.1

          6. 5) 8081 -> 60738 [ACK] Seq=1 ACK=396 Win=30336 Len=0

          7. 6) HTTP/1.1 200 (text/html)

          8. 7) 60738 -> 8081 [ACK] Seq=396 ACK=120 Win=66560 Len=0


          9. ------------------斷開(kāi)連接-----------------------------

          10. 8) 60738 -> 8081 [FIN ACK] Seq=396 Ack=120 Win=66560 Len=0

          11. 9) 8081 -> 60738 [FIN ACK] Seq=120 Ack=397 Win=30336 Len=0

          12. 10) 60738 -> 8081 [ACK] Seq=397 Ack=121 Win=66560 Len=0

          我們根據(jù)上面的流程梳理,可以知道, 序號(hào)1序號(hào)3是明顯的三次握手,然后 序號(hào)4進(jìn)行了一次 HTTP 請(qǐng)求,接著 序號(hào)5是對(duì) HTTP 請(qǐng)求的一次接收確認(rèn), 序號(hào)6是響應(yīng) HTTP 請(qǐng)求, 序號(hào)7是對(duì)響應(yīng)請(qǐng)求的確認(rèn)。


          B) 四次揮手

          上述序號(hào) 8910 是我關(guān)閉瀏覽器后抓到的包,既然是關(guān)閉瀏覽器,我們肯定知道就是 TCP 連接的斷開(kāi)了。這里有同學(xué)應(yīng)該已經(jīng)發(fā)現(xiàn)了問(wèn)題了,我們的斷開(kāi)是 4次揮手,你這抓的包只有三條記錄,是你寫(xiě)錯(cuò)了吧?我要告訴你的是,我沒(méi)有寫(xiě)錯(cuò),這是真實(shí)的抓包抓的,至于為什么是三次,我們來(lái)分析一下:

          正常情況下,連接斷開(kāi)是 4次揮手的, 4次揮手過(guò)程如下圖:

          我們分析這圖,揮手流程是這樣的:

          1. 1. 客戶端發(fā)起一個(gè)斷開(kāi)請(qǐng)求,進(jìn)入 FIN-WAIT 狀態(tài)

          2. 2. 服務(wù)端確認(rèn)斷開(kāi)請(qǐng)求

          3. 3. 服務(wù)端立即發(fā)送一個(gè)斷開(kāi)請(qǐng)求,進(jìn)入 CLOSE-WAIT 狀態(tài)

          4. 4. 客戶端確認(rèn)服務(wù)端斷開(kāi)請(qǐng)求,進(jìn)入 TIME-WAIT 狀態(tài)

          我們發(fā)現(xiàn)上面的 流程2和 流程3都是由服務(wù)端發(fā)起的,那么有沒(méi)有可能合并這兩個(gè)請(qǐng)求,一次發(fā)送給客戶端?答案是 可以。在 RFC 2581中的 4.2 節(jié)有提到, ack可以延遲確認(rèn),只要求保證在 500ms之內(nèi)保證確認(rèn)包到達(dá)即可。在這樣的標(biāo)準(zhǔn)下, TCP確認(rèn)是有可能進(jìn)行合并延遲確認(rèn)的,所以,根據(jù)這一點(diǎn),我們推斷下面這個(gè)包:

          1. 9) 8081 -> 60738 [FIN ACK] Seq=120 Ack=397 Win=30336 Len=0

          合并了對(duì)客戶端的 ack確認(rèn)以及服務(wù)端發(fā)送的 FIN斷開(kāi)信號(hào)包。我們點(diǎn)擊該包詳情如下:這里紅框中體現(xiàn)了,這個(gè) 9號(hào)包是對(duì) Frame500 的 ACK 確認(rèn),我們根據(jù)最開(kāi)始的截圖可以知道,這個(gè)包就是 8號(hào)包

          1. 8) 60738 -> 8081 [FIN ACK] Seq=396 Ack=120 Win=66560 Len=0

          并且 9號(hào)包 本身自己是發(fā)送的 FIN 信號(hào)包,所以,我們可以認(rèn)為 9號(hào)包合并了 ACK 和 FIN 的內(nèi)容,所以通常的 4次揮手,經(jīng)過(guò)合并后變成了 3次揮手。

          以上就是一個(gè) HTTP 完整的請(qǐng)求,整個(gè)流程用圖表示如下:


          C) Keep-Alive

          • 這里肯定有同學(xué)會(huì)問(wèn),既然這是一次完整的 HTTP 請(qǐng)求,那么是不是每次請(qǐng)求都會(huì)有三次握手嗎?

          答案是:目前的協(xié)議是不用的

          在 HTTP0.9 版本和 HTTP1.0 版本中,每次請(qǐng)求響應(yīng)都是要三次握手的, 但是 HTTP1.0 開(kāi)始嘗試持續(xù)連接,也就是 Keep-Alive 參數(shù),但是官方還沒(méi)有正式支持,在 HTTP1.1協(xié)議中,官方默認(rèn)就是支持 Keep-Alive 參數(shù)的,默認(rèn)是持續(xù)連接。 Keep-Alive 的作用主要有兩點(diǎn):

          1. 1.檢查死節(jié)點(diǎn)

          2. 2.防止連接由于不活躍而斷開(kāi)

          • 檢查死節(jié)點(diǎn)

          主要是為了讓連接快速失敗被發(fā)現(xiàn),可以進(jìn)行重新連接,比如 A 和 B 兩端已經(jīng)建立了連接, B節(jié)點(diǎn)因?yàn)?異常原因掛掉了,同時(shí) A 節(jié)點(diǎn)并不知道,這時(shí)候有兩種情況:

          1.假設(shè) B 節(jié)點(diǎn)還沒(méi)有恢復(fù),那么 B 節(jié)點(diǎn)不會(huì)回復(fù) ACK, A節(jié)點(diǎn)就會(huì)一直重試,重試到一定次數(shù)才能知道 B 節(jié)點(diǎn)是死節(jié)點(diǎn)。

          2. B節(jié)點(diǎn)在 A發(fā)送數(shù)據(jù)之前重啟成功了,這個(gè)時(shí)候 A節(jié)點(diǎn)發(fā)送數(shù)據(jù), B節(jié)點(diǎn)并不會(huì)接受,而是會(huì)發(fā)送一個(gè) RST 信號(hào)(在一個(gè)已關(guān)閉的 socket 上收到數(shù)據(jù)時(shí),將發(fā)送 RST數(shù)據(jù)包,要求對(duì)端關(guān)閉異常連接且對(duì)端不需要回復(fù) ACK),然后 A 才知道 B 節(jié)點(diǎn)需要重連了。

          以上兩種情況,都會(huì)導(dǎo)致只有到發(fā)送數(shù)據(jù)的時(shí)候才知道對(duì)方已經(jīng)出異常了。而 Keep-Alive 每隔一段時(shí)間就會(huì)發(fā)送心跳,就可以很快的知道服務(wù)端節(jié)點(diǎn)的情況。

          • 防止連接由于不活躍而斷開(kāi)

          我們知道,網(wǎng)絡(luò)連接的建立和維持是消耗資源的,一個(gè)服務(wù)器上能建立的連接是有限的,所以像防火墻或者操作系統(tǒng)中會(huì)為了節(jié)省資源會(huì)釋放掉不活躍的連接,而 Keep-Alive 每隔一段時(shí)間發(fā)送一個(gè)心跳包,就是告訴防火墻或者操作系統(tǒng),我這個(gè)連接是活躍的,不要?dú)⑽摇?/p>

          后來(lái)重新抓了一次帶有 Keep-Alive 的包,截圖如下:

          在上圖中最后兩個(gè)包就是發(fā)的 Keep-Alive 包,然后服務(wù)端進(jìn)行 ACK 確認(rèn),我們看到 keep-alive 包,實(shí)際上是會(huì)發(fā)帶有一個(gè)字節(jié)的包,這就是 keep-alive 的實(shí)現(xiàn)。

          說(shuō)完 Keep-Alive,我們回到最開(kāi)始的問(wèn)題,為啥一次 HTTP 請(qǐng)求會(huì)有進(jìn)行兩個(gè)端口的握手呢?其實(shí),這個(gè)和協(xié)議本身沒(méi)有任何關(guān)系,第一個(gè)抓包的截圖是用谷歌瀏覽器訪問(wèn)的,最后一個(gè)抓包圖是用火狐瀏覽器訪問(wèn)的,仔細(xì)對(duì)比我們發(fā)現(xiàn),火狐瀏覽器只有一個(gè)端口三次握手。所以這種情況的發(fā)生就是瀏覽器自身的實(shí)現(xiàn),谷歌瀏覽器為什么會(huì)這么實(shí)現(xiàn),猜測(cè)是:盡可能的保證HTTP訪問(wèn)的可用性,當(dāng)某個(gè)端口不可用,可以立即切換到另外一個(gè)端口,完成HTTP的請(qǐng)求和響應(yīng)。(個(gè)人猜測(cè),如果有權(quán)威解答,可以評(píng)論區(qū)交流)

          總結(jié)


          • HTTP 請(qǐng)求是依托于 TCP 連接的,第一次連接的時(shí)候會(huì)進(jìn)行 TCP 的三次握手。

          • HTTP 通過(guò) Keep-Alive 來(lái)進(jìn)行持久連接,通過(guò)定時(shí)發(fā)送一個(gè)心跳包,來(lái)告訴服務(wù)端自己還活躍。

          • HTTP 連接的斷開(kāi)也會(huì)導(dǎo)致 TCP的四次揮手,但是如果服務(wù)器判斷滿足條件,會(huì)合并 ACK 和 FIN 信號(hào),進(jìn)而轉(zhuǎn)化為三次揮手。


          - END -

          公眾號(hào)后臺(tái)回復(fù)「加群」加入一線高級(jí)工程師技術(shù)交流群,一起交流進(jìn)步。

           推薦閱讀 

          Kubernetes 運(yùn)維架構(gòu)師實(shí)戰(zhàn)集訓(xùn)營(yíng)【本周開(kāi)課】
          31天拿下K8s含金量最高的CKA證書(shū)!
          K8s常見(jiàn)問(wèn)題:Service 不能訪問(wèn)排查流程
          Docker環(huán)境部署Prometheus+Grafana監(jiān)控系統(tǒng)
          Zabbix 通過(guò) API 監(jiān)控 Kubernetes
          Kubernetes 學(xué)習(xí)筆記總結(jié),超詳細(xì)!
          Kubernetes生產(chǎn)環(huán)境最佳實(shí)踐
          高性能 Nginx HTTPS 調(diào)優(yōu) - 如何為 HTTPS 提速 30%



          點(diǎn)亮,服務(wù)器三年不宕機(jī)

          瀏覽 47
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  91久久久18久久久 | 看黄色免费片 | 亚洲欧美婷婷五月色综合 | 亚洲AV无码人妻 | 午夜香蕉网 |