免费视频淫片aa毛片_日韩高清在线亚洲专区vr_日韩大片免费观看视频播放_亚洲欧美国产精品完整版

打開APP
userphoto
未登錄

開通VIP,暢享免費(fèi)電子書等14項(xiàng)超值服

開通VIP
爬蟲核心原理:一次 HTTP 請(qǐng)求到底是如何完成的?


源 / 馬哥Linux運(yùn)維

文中很多細(xì)節(jié)就是面試時(shí)關(guān)于“網(wǎng)絡(luò)”這一塊所常問的,還是得多積累一點(diǎn)

概   覽

上一篇文章 當(dāng)你 ping 的時(shí)候,你知道背后發(fā)生了什么嗎?通過實(shí)際抓包來分析了一次 Ping 的過程(面試常問),我們知道了 ping 是依托于 ICMP 協(xié)議,然后再局域網(wǎng)中還會(huì)涉及到 ARP 請(qǐng)求,今天這篇文章我們同樣用抓包分析工具來分析我們熟悉的 HTTP 請(qǐng)求是怎么樣的?

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

本來是想找個(gè)網(wǎng)站進(jìn)行抓包分析的,但是正式環(huán)境的網(wǎng)站 HTTP 請(qǐng)求太多,干擾太多,對(duì)分析不太友好,所以簡單些了一個(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)成功訪問如下:


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

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


抓包分析

A) 三次握手

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

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

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

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

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

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

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

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

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

  • Win: TCP 窗口大小

  • Len: 消息長度

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

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

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

對(duì)于上面的概念,這里簡單解釋下,再介紹之前我們先看 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)窗口,通過動(dòng)態(tài)調(diào)整窗口大小,來控制發(fā)送數(shù)據(jù)的速率。上圖中占用 2個(gè)字節(jié),也就是 16位,那么可以支持的最大數(shù)就是 2^16=65536,所以默認(rèn)情況下 TCP頭部標(biāo)記能支持的最大窗口數(shù)是 65536字節(jié),也就是 64KB。

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

3. Mss: 最大報(bào)文段長度這個(gè)就是規(guī)定最大的能傳輸報(bào)文的長度,為了達(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)整因子在前面說 TCP 窗口大小中我們說到,默認(rèn)情況下, TCP 窗口大小最大只能支持 64KB的緩沖數(shù)據(jù),在今天這個(gè)高速上網(wǎng)時(shí)代,這個(gè)大小肯定不滿足條件了,所以,為了能夠支持更多的緩沖數(shù)據(jù) RFC 1323中就規(guī)定了 TCP 的擴(kuò)展選項(xiàng),其中窗口縮放調(diào)整因子就是其中之一,這個(gè)是如何起作用的呢?首先說明,這個(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),也就是說,發(fā)送 ABC 個(gè)包,如果我收到了 AC的包, B沒有收到,那么對(duì)于 C,這個(gè)包我是不會(huì)確認(rèn)的,需要等 B這個(gè)包收到后再確認(rèn),那么 TCP有超時(shí)重傳機(jī)制,如果一個(gè)包很久沒有確認(rèn),就會(huì)當(dāng)它丟失了,進(jìn)行重傳,這樣會(huì)造成很多多余的包重傳,浪費(fèi)傳輸空間。為了解決這個(gè)問題, SACK就提出了選擇性確認(rèn)機(jī)制,啟用 SACK 后,接受端會(huì)確認(rèn)所有收到的包,這樣發(fā)送端就只用重傳真正丟失的包了。


簡單介紹了上面的基礎(chǔ)概念后,我們來根據(jù)抓包梳理下 HTTP 請(qǐng)求的過程,根據(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. ------------------斷開連接-----------------------------

  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 連接的斷開了。這里有同學(xué)應(yīng)該已經(jīng)發(fā)現(xiàn)了問題了,我們的斷開是 4次揮手,你這抓的包只有三條記錄,是你寫錯(cuò)了吧?我要告訴你的是,我沒有寫錯(cuò),這是真實(shí)的抓包抓的,至于為什么是三次,我們來分析一下:

正常情況下,連接斷開是 4次揮手的, 4次揮手過程如下圖:

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

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

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

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

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

我們發(fā)現(xiàn)上面的 流程2和 流程3都是由服務(wù)端發(fā)起的,那么有沒有可能合并這兩個(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斷開信號(hào)包。我們點(diǎn)擊該包詳情如下: 這里紅框中體現(xiàn)了,這個(gè) 9號(hào)包是對(duì) Frame500 的 ACK 確認(rèn),我們根據(jù)最開始的截圖可以知道,這個(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)過合并后變成了 3次揮手。

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


C) Keep-Alive

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

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

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

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

  2. 2.防止連接由于不活躍而斷開

  • 檢查死節(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)還沒有恢復(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)的情況。

  • 防止連接由于不活躍而斷開

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

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

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

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


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

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

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

本站僅提供存儲(chǔ)服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊舉報(bào)。
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
深入理解Loadrunner中的Browser Emulation
圖解 | 原來這就是TCP
基于TCp的數(shù)據(jù)包傳輸過程
打開過各種網(wǎng)站的你,想要了解一下HTTP協(xié)議嗎?
知識(shí)梳理-網(wǎng)絡(luò)基礎(chǔ)
3年多前端菜雞的面試及知識(shí)梳理(二)
更多類似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長圖 關(guān)注 下載文章
綁定賬號(hào)成功
后續(xù)可登錄賬號(hào)暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服