天天看點

原來你是這樣的Websocket--抓包分析Chrome控制台Fiddler:抓包調試利器WireShark

之前自己一個人負責完成了公司的消息推送服務,和移動端配合完成了掃碼登入、訂單消息推送、活動消息廣播等功能。為了加深自己對Websocket協定的了解,自己通過進行抓包的方式學習了一番。現在分享出來,希望對大家能有所幫助。

Chrome控制台

(1)F12進入控制台,點選Network,選中ws欄,注意選中Filter。

原來你是這樣的Websocket--抓包分析Chrome控制台Fiddler:抓包調試利器WireShark

(2)重新整理頁面會得到一個ws連結。

原來你是這樣的Websocket--抓包分析Chrome控制台Fiddler:抓包調試利器WireShark

(3)點選連結可以檢視連結詳情

原來你是這樣的Websocket--抓包分析Chrome控制台Fiddler:抓包調試利器WireShark

注意紅框标出的資訊,後面會詳細說明。

(4)當然也可以切換到Frames檢視發出和接收的消息,但是非常的簡陋,隻能看到消息内容,資料長度和時間

原來你是這樣的Websocket--抓包分析Chrome控制台Fiddler:抓包調試利器WireShark

Fiddler:抓包調試利器

(1)打開Fiddler,點開菜單欄的Rules,選擇Customize Rules...

原來你是這樣的Websocket--抓包分析Chrome控制台Fiddler:抓包調試利器WireShark

(2)這時會打開CustomRules.js檔案,在class Handlers中加入以下代碼

static function OnWebSocketMessage(oMsg: WebSocketMessage) {
        // Log Message to the LOG tab
        FiddlerApplication.Log.LogString(oMsg.ToString());
    }                
原來你是這樣的Websocket--抓包分析Chrome控制台Fiddler:抓包調試利器WireShark

(3)儲存後就可以在Fiddler右邊欄的Log标簽裡,看到WebSocket的資料包

下列圖中紅框标出的Client.1代表用戶端發出的第一條消息;對應的Server.1代表服務端發出的第一條消息。MessageType:Text代表正常的通話消息;Close代表會話關閉。

用戶端發出的消息:

原來你是這樣的Websocket--抓包分析Chrome控制台Fiddler:抓包調試利器WireShark

服務端發出的消息:

原來你是這樣的Websocket--抓包分析Chrome控制台Fiddler:抓包調試利器WireShark

然後我們會發現每次會話關閉都是由用戶端發起的:

原來你是這樣的Websocket--抓包分析Chrome控制台Fiddler:抓包調試利器WireShark

相對于Chrome控制台來說Fiddler抓包更加詳細一些,能知道會話消息是由用戶端還是服務端發出并且能知道消息類型。但是這仍然滿足不了深入了解學習Websocket協定的目的。如果是處理HTTP、HTTPS,還是用Fiddler。其他協定比如TCP,UDP 就用WireShark。TPC/IP協定是傳輸層協定,主要解決資料如何在網絡中傳輸,而HTTP、Websocket是應用層協定,主要解決如何包裝資料。因為應用層是在傳輸層的基礎上包裝資料,是以我們還是從底層開始了解Websocket到底是個啥?是如何工作的?

WireShark

WireShark(前稱Ethereal)是一個網絡封包分析軟體。網絡封包分析軟體的功能是撷取網絡封包,并盡可能顯示出最為詳細的網絡封包資料。WireShark抓包是根據TCP/IP五層協定來的,也就是實體層、資料鍊路層、網絡層、傳輸層、應用層。我們主要關注傳輸層和應用層。

TCP三向交握

我們都知道,TCP建立連接配接時,會有三次握手過程。下圖是WireShark截獲到的三次握手的三個資料包(雖然叫資料包,但是三次握手包是沒有資料的)。

原來你是這樣的Websocket--抓包分析Chrome控制台Fiddler:抓包調試利器WireShark

點選上圖中的資料包就可以檢視每個資料包的詳情,這裡我們需要明确幾個概念才能看懂每個資料包代表啥意義:

SYN:同步比特,建立連接配接。

ACK:确認比特,置1表示這是一個确認的TCP包,0則不是。

PSH:推送比特,當發送端PSH=1時,接收端應盡快傳遞給應用程序。

  • 第一次握手

可以看到我們打開的Transmission Control Protocol即為傳輸層(Tcp)

SYN置為1,用戶端向服務端發送連接配接請求包。

原來你是這樣的Websocket--抓包分析Chrome控制台Fiddler:抓包調試利器WireShark
  • 第二次握手

伺服器收到用戶端發過來的TCP封包,由SYN=1知道用戶端要求建立聯機,向用戶端發送一個SYN=1,ACK=1的TCP封包,将确認序号設定為用戶端的序列号加1。

原來你是這樣的Websocket--抓包分析Chrome控制台Fiddler:抓包調試利器WireShark
  • 第三次握手

用戶端接收到伺服器發過來的包後檢查确認序列号是否正确,即第一次發送的序号+1,以及标志位ACK是否為1。若正确則再次發送确認包,ACK标志為1。連結建立成功,可以發送資料了。

原來你是這樣的Websocket--抓包分析Chrome控制台Fiddler:抓包調試利器WireShark

一次特殊的HTTP請求

緊接着是一次Http請求(第四個包),說明Http的确是使用Tcp建立連接配接的。

先來看傳輸層(Tcp): PSH(推送比特)置1,ACK置1,PSH置1說明開始發送資料,同時發送資料ACK要置1,因為需要接收到這個資料包的端給予确認。PSH為1的情況,一般隻出現在 DATA内容不為0的包中,也就是說PSH為1表示的是有真正的TCP資料包内容被傳遞。

原來你是這樣的Websocket--抓包分析Chrome控制台Fiddler:抓包調試利器WireShark

再來看應用層(Http):這是一次特殊的Http請求,為什麼是一次特殊的Http請求呢?Http請求頭中Connection:Upgrade Upgrade:websocket,Upgrade代表更新到較新的Http協定或者切換到不同的協定。很明顯WebSocket使用此機制以相容的方式與HTTP伺服器建立連接配接。WebSocket協定有兩個部分:握手建立更新後的連接配接,然後進行實際的資料傳輸。首先,用戶端通過使用Upgrade: WebSocket和Connection: Upgrade頭部以及一些特定于協定的頭來請求WebSocket連接配接,以建立正在使用的版本并設定握手。伺服器,如果它支援協定,回複與相同Upgrade: WebSocket和Connection: Upgrade标題,并完成握手。握手完成後,資料傳輸開始。這些資訊在前面的Chrome控制台中也可以看到。

請求:

原來你是這樣的Websocket--抓包分析Chrome控制台Fiddler:抓包調試利器WireShark

響應:

響應狀态碼 101 表示伺服器已經了解了用戶端的請求,在發送完這個響應後,伺服器将會切換到在Upgrade請求頭中定義的那些協定。

原來你是這樣的Websocket--抓包分析Chrome控制台Fiddler:抓包調試利器WireShark

由此我們可以總結出:

Websocket協定本質上是一個基于TCP的協定。建立連接配接需要握手,用戶端(浏覽器)首先向伺服器(web server)發起一條特殊的http請求,web server解析後生成應答到浏覽器,這樣子一個websocket連接配接就建立了,直到某一方關閉連接配接。

Websocket的世界

通信協定格式是WebSocket格式,伺服器端采用Tcp Socket方式接收資料,進行解析,協定格式如下:

原來你是這樣的Websocket--抓包分析Chrome控制台Fiddler:抓包調試利器WireShark

首先我們需要知道資料在實體層,資料鍊路層是以二進制進行傳遞的,而在應用層是以16進制位元組流進行傳輸的。

第一個位元組:

原來你是這樣的Websocket--抓包分析Chrome控制台Fiddler:抓包調試利器WireShark

FIN:1位,用于描述消息是否結束,如果為1則該消息為消息尾部,如果為零則還有後續資料包;

RSV1,RSV2,RSV3:各1位,用于擴充定義的,如果沒有擴充約定的情況則必須為0

OPCODE:4位,用于表示消息接收類型,如果接收到未知的opcode,接收端必須關閉連接配接。

Webdocket資料幀中OPCODE定義:

0x0表示附加資料幀

0x1表示文本資料幀

0x2表示二進制資料幀

0x3-7暫時無定義,為以後的非控制幀保留

0x8表示連接配接關閉

0x9表示ping

0xA表示pong

0xB-F暫時無定義,為以後的控制幀保留

第二個位元組:

原來你是這樣的Websocket--抓包分析Chrome控制台Fiddler:抓包調試利器WireShark

MASK:1位,用于辨別PayloadData是否經過掩碼處理,用戶端發出的資料幀需要進行掩碼處理,是以此位是1。資料需要解碼。

PayloadData的長度:7位,7+16位,7+64位

如果其值在0-125,則是payload的真實長度。

如果值是126,則後面2個位元組形成的16位無符号整型數的值是payload的真實長度。

如果值是127,則後面8個位元組形成的64位無符号整型數的值是payload的真實長度。

原來你是這樣的Websocket--抓包分析Chrome控制台Fiddler:抓包調試利器WireShark

上圖是用戶端發送給服務端的資料包,其中PayloadData的長度為二進制:01111110——>十進制:126;如果值是126,則後面2個位元組形成的16位無符号整型數的值是payload的真實長度。也就是圈紅的十六進制:00C1——>十進制:193 byte。是以PayloadData的真實資料長度是193 bytes;

根據我們的分析,用戶端到服務端資料包的websocket幀圖應該為:

原來你是這樣的Websocket--抓包分析Chrome控制台Fiddler:抓包調試利器WireShark

我們再來抓包分析一下伺服器到用戶端的資料包:

原來你是這樣的Websocket--抓包分析Chrome控制台Fiddler:抓包調試利器WireShark

可以發現伺服器發送給用戶端的資料包中第二個位元組中MASK位為0,這說明伺服器發送的資料幀未經過掩碼處理,這個我們從用戶端和服務端的資料包截圖中也可以發現,用戶端的資料被加密處理,而服務端的資料則沒有。(如果伺服器收到用戶端發送的未經掩碼處理的資料包,則會自動斷開連接配接;反之,如果用戶端收到了服務端發送的經過掩碼處理的資料包,也會自動斷開連接配接)。

掩碼處理:

原來你是這樣的Websocket--抓包分析Chrome控制台Fiddler:抓包調試利器WireShark

未掩碼處理:

原來你是這樣的Websocket--抓包分析Chrome控制台Fiddler:抓包調試利器WireShark

根據我們的分析,服務端到用戶端資料包的websocket幀圖應該為:

原來你是這樣的Websocket--抓包分析Chrome控制台Fiddler:抓包調試利器WireShark

TCP KeepAlive

原來你是這樣的Websocket--抓包分析Chrome控制台Fiddler:抓包調試利器WireShark

如上圖所示,TCP保活封包總是成對出現,包括TCP保活探測封包和TCP保活探測确認封包。

TCP保活探測封包是将之前TCP封包的确認序列号減1,并設定1個位元組,内容為“00”的應用層資料,如下圖所示:

原來你是這樣的Websocket--抓包分析Chrome控制台Fiddler:抓包調試利器WireShark

TCP保活探測确認封包就是對保活探測封包的确認,其封包格式如下:

原來你是這樣的Websocket--抓包分析Chrome控制台Fiddler:抓包調試利器WireShark

因為Websocket通過Tcp Socket方式工作,現在考慮一個問題,在一次長連接配接中,伺服器怎麼知道消息的順序呢?這就涉及到tcp的序列号(Sequence Number)和确認号(Acknowledgment Number)。我的了解是序列号是發送的資料長度;确認号是接收的資料長度。這樣講比較抽象,我們從TCP三向交握開始(結合下圖)詳細分析一下。

原來你是這樣的Websocket--抓包分析Chrome控制台Fiddler:抓包調試利器WireShark

包1:

TCP會話的每一端的序列号都從0開始,同樣的,确認号也從0開始,因為此時通話還未開始,沒有通話的另一端需要确認

包2:

服務端響應用戶端的請求,響應中附帶序列号0(由于這是服務端在該次TCP會話中發送的第一個包,是以序列号為0)和相對确認号1(表明服務端收到了用戶端發送的包1中的SYN)。需要注意的是,盡管用戶端沒有發送任何有效資料,确認号還是被加1,這是因為接收的包中包含SYN或FIN标志位。

包3:

和包2中一樣,用戶端使用确認号1響應服務端的序列号0,同時響應中也包含了用戶端自己的序列号(由于服務端發送的包中确認收到了用戶端發送的SYN,故用戶端的序列号由0變為1)此時,通信的兩端的序列号都為1。

包4:用戶端——>伺服器

這是流中第一個攜帶有效資料的包(确切的說,是用戶端發送的HTTP請求),序列号依然為1,因為到上個包為止,還沒有發送任何資料,确認号也保持1不變,因為用戶端沒有從服務端接收到任何資料。需要注意的是,包中有效資料的長度為505位元組

包5:伺服器——>用戶端

當上層處理HTTP請求時,服務端發送該包來确認用戶端在包4中發來的資料,需要注意的是,确認号的值增加了505(505是包4中有效資料長度),變為506,簡單來說,服務端以此來告知用戶端端,目前為止,我總共收到了506位元組的資料,服務端的序列号保持為1不變。

包6:伺服器——>用戶端

這個包标志着服務端傳回HTTP響應的開始,序列号依然為1,因為服務端在該包之前傳回的包中都不帶有有效資料,該包帶有129位元組的有效資料。

包7:

由于上個資料包的發送,TCP用戶端的确認序列号增長至130,從服務端接收了129位元組的資料,用戶端的确認号由1增長至130

了解了序列号和确認序列号是怎麼工作的之後,我們也就知道“TCP保活探測封包是将之前TCP封包的确認序列号減1,并設定1個位元組”為什麼要這麼搞了。減一再加一,是為了保證一次連接配接中keep alive不影響序列号和确認序列号。Keep alive 中的1byte 00的資料并不是真正要傳遞的資料,而是tcp keep alive約定俗稱的規則。

總結:

WebSocket 是一個獨立的基于 TCP 的協定,它與 HTTP 之間的唯一關系就是它的握手請求可以作為一個更新請求(Upgrade request)經由 HTTP 伺服器解釋。再嚴謹一點:WebSocket是一個網絡通訊協定, 隻要了解上面的資料幀格式和握手流程, 都可以完成基于websokect的即時通訊。

轉載于:https://www.cnblogs.com/songwenjie/p/8575579.html

繼續閱讀