小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

爬蟲核心原理:一次 HTTP 請求到底是如何完成的?

 格瑞思n5c5alhf 2019-06-27


源 / 馬哥Linux運維

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

概   覽

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

環(huán)境準備

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

環(huán)境:

  1. 1.響應http請求的服務demo

  2. 2.客戶端ip:192.168.2.135

  3. 3.服務端:45.76.105.92

  4. 4.抓包工具:Wireshark

把 demo部署到服務器,啟動成功訪問如下:


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

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


抓包分析

A) 三次握手

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

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

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

我們先看第一次請求:

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

我們來解析下這段包請求信息:

  • 60783->8081 端口號:源端口--->目標端口

  • [SYN] :同步握手信號

  • Seq : 消息編號

  • Win: TCP 窗口大小

  • Len: 消息長度

  • Mss: 最大報文段長度

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

  • SACK_PERM : SACK選項,這里等于1表示開啟 SACK。

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

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

2. Len: 消息長度 就是指數(shù)據(jù)報文段,因為整個 TCP報文 = Header + packSize,所以這個消息長度就是指要傳送的數(shù)據(jù)包總共長度,在本次分析中也就是 HTTP報文的大小。

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

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

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

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

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

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


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

  1. ------------------------請求連接--------------------------

  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ù)上面的流程梳理,可以知道, 序號1序號3是明顯的三次握手,然后 序號4進行了一次 HTTP 請求,接著 序號5是對 HTTP 請求的一次接收確認, 序號6是響應 HTTP 請求, 序號7是對響應請求的確認。


B) 四次揮手

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

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

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

  1. 1. 客戶端發(fā)起一個斷開請求,進入 FIN-WAIT 狀態(tài)

  2. 2. 服務端確認斷開請求

  3. 3. 服務端立即發(fā)送一個斷開請求,進入 CLOSE-WAIT 狀態(tài)

  4. 4. 客戶端確認服務端斷開請求,進入 TIME-WAIT 狀態(tài)

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

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

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

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

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

以上就是一個 HTTP 完整的請求,整個流程用圖表示如下:


C) Keep-Alive

  • 這里肯定有同學會問,既然這是一次完整的 HTTP 請求,那么是不是每次請求都會有三次握手嗎?

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

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

  1. 1.檢查死節(jié)點

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

  • 檢查死節(jié)點

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

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

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

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

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

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

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

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

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


總   結(jié)
  • HTTP 請求是依托于 TCP 連接的,第一次連接的時候會進行 TCP 的三次握手。

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

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

    本站是提供個人知識管理的網(wǎng)絡存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多