原來你是這樣的Websocket--抓包分析

以前本身一我的負責完成了公司的消息推送服務,和移動端配合完成了掃碼登陸、訂單消息推送、活動消息廣播等功能。爲了加深本身對Websocket協議的理解,本身經過進行抓包的方式學習了一番。如今分享出來,但願對你們能有所幫助。javascript

Chrome控制檯

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

(2)刷新頁面會獲得一個ws連接。
java

(3)點擊連接能夠查看連接詳情
web

注意紅框標出的信息,後面會詳細說明。
(4)固然也能夠切換到Frames查看發出和接收的消息,可是很是的簡陋,只能看到消息內容,數據長度和時間
chrome

Fiddler:抓包調試利器

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

(2)這時會打開CustomRules.js文件,在class Handlers中加入如下代碼服務器

static function OnWebSocketMessage(oMsg: WebSocketMessage) { // Log Message to the LOG tab FiddlerApplication.Log.LogString(oMsg.ToString()); }

(3)保存後就能夠在Fiddler右邊欄的Log標籤裏,看到WebSocket的數據包
下列圖中紅框標出的Client.1表明客戶端發出的第一條消息;對應的Server.1表明服務端發出的第一條消息。MessageType:Text表明正常的通話消息;Close表明會話關閉。
客戶端發出的消息:
websocket

服務端發出的消息:
網絡

而後咱們會發現每次會話關閉都是由客戶端發起的:
socket

相對於Chrome控制檯來講Fiddler抓包更加詳細一些,能知道會話消息是由客戶端仍是服務端發出而且能知道消息類型。可是這仍然知足不了深刻理解學習Websocket協議的目的。若是是處理HTTP、HTTPS,仍是用Fiddler。其餘協議好比TCP,UDP 就用WireShark。TPC/IP協議是傳輸層協議,主要解決數據如何在網絡中傳輸,而HTTP、Websocket是應用層協議,主要解決如何包裝數據。由於應用層是在傳輸層的基礎上包裝數據,因此咱們仍是從底層開始瞭解Websocket究竟是個啥?是如何工做的?

WireShark

WireShark(前稱Ethereal)是一個網絡封包分析軟件。網絡封包分析軟件的功能是擷取網絡封包,並儘量顯示出最爲詳細的網絡封包資料。WireShark抓包是根據TCP/IP五層協議來的,也就是物理層、數據鏈路層、網絡層、傳輸層、應用層。咱們主要關注傳輸層和應用層。

TCP三次握手

咱們都知道,TCP創建鏈接時,會有三次握手過程。下圖是WireShark截獲到的三次握手的三個數據包(雖然叫數據包,可是三次握手包是沒有數據的)。

點擊上圖中的數據包就能夠查看每一個數據包的詳情,這裏咱們須要明確幾個概念才能看懂每一個數據包表明啥意義:
SYN:同步比特,創建鏈接。
ACK:確認比特,置1表示這是一個確認的TCP包,0則不是。
PSH:推送比特,當發送端PSH=1時,接收端應儘快交付給應用進程。

  • 第一次握手

能夠看到咱們打開的Transmission Control Protocol即爲傳輸層(Tcp)
SYN置爲1,客戶端向服務端發送鏈接請求包。

  • 第二次握手

服務器收到客戶端發過來的TCP報文,由SYN=1知道客戶端要求創建聯機,向客戶端發送一個SYN=1,ACK=1的TCP報文,將確認序號設置爲客戶端的序列號加1。

  • 第三次握手

客戶端接收到服務器發過來的包後檢查確認序列號是否正確,即第一次發送的序號+1,以及標誌位ACK是否爲1。若正確則再次發送確認包,ACK標誌爲1。連接創建成功,能夠發送數據了。

一次特殊的HTTP請求

緊接着是一次Http請求(第四個包),說明Http的確是使用Tcp創建鏈接的。

先來看傳輸層(Tcp): PSH(推送比特)置1,ACK置1,PSH置1說明開始發送數據,同時發送數據ACK要置1,由於須要接收到這個數據包的端給予確認。PSH爲1的狀況,通常只出如今 DATA內容不爲0的包中,也就是說PSH爲1表示的是有真正的TCP數據包內容被傳遞。

再來看應用層(Http):這是一次特殊的Http請求,爲何是一次特殊的Http請求呢?Http請求頭中Connection:Upgrade Upgrade:websocket,Upgrade表明升級到較新的Http協議或者切換到不一樣的協議。很明顯WebSocket使用此機制以兼容的方式與HTTP服務器創建鏈接。WebSocket協議有兩個部分:握手創建升級後的鏈接,而後進行實際的數據傳輸。首先,客戶端經過使用Upgrade: WebSocket和Connection: Upgrade頭部以及一些特定於協議的頭來請求WebSocket鏈接,以創建正在使用的版本並設置握手。服務器,若是它支持協議,回覆與相同Upgrade: WebSocket和Connection: Upgrade標題,並完成握手。握手完成後,數據傳輸開始。這些信息在前面的Chrome控制檯中也能夠看到。

請求:

響應:
響應狀態碼 101 表示服務器已經理解了客戶端的請求,在發送完這個響應後,服務器將會切換到在Upgrade請求頭中定義的那些協議。

由此咱們能夠總結出:
Websocket協議本質上是一個基於TCP的協議。創建鏈接須要握手,客戶端(瀏覽器)首先向服務器(web server)發起一條特殊的http請求,web server解析後生成應答到瀏覽器,這樣子一個websocket鏈接就創建了,直到某一方關閉鏈接。

Websocket的世界

通訊協議格式是WebSocket格式,服務器端採用Tcp Socket方式接收數據,進行解析,協議格式以下:

首先咱們須要知道數據在物理層,數據鏈路層是以二進制進行傳遞的,而在應用層是以16進制字節流進行傳輸的。

第一個字節:

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暫時無定義,爲之後的控制幀保留

第二個字節:

MASK:1位,用於標識PayloadData是否通過掩碼處理,客戶端發出的數據幀須要進行掩碼處理,因此此位是1。數據須要解碼。
PayloadData的長度:7位,7+16位,7+64位
若是其值在0-125,則是payload的真實長度。
若是值是126,則後面2個字節造成的16位無符號整型數的值是payload的真實長度。
若是值是127,則後面8個字節造成的64位無符號整型數的值是payload的真實長度。

上圖是客戶端發送給服務端的數據包,其中PayloadData的長度爲二進制:01111110——>十進制:126;若是值是126,則後面2個字節造成的16位無符號整型數的值是payload的真實長度。也就是圈紅的十六進制:00C1——>十進制:193 byte。因此PayloadData的真實數據長度是193 bytes;

根據咱們的分析,客戶端到服務端數據包的websocket幀圖應該爲:

咱們再來抓包分析一下服務器到客戶端的數據包:

能夠發現服務器發送給客戶端的數據包中第二個字節中MASK位爲0,這說明服務器發送的數據幀未通過掩碼處理,這個咱們從客戶端和服務端的數據包截圖中也能夠發現,客戶端的數據被加密處理,而服務端的數據則沒有。(若是服務器收到客戶端發送的未經掩碼處理的數據包,則會自動斷開鏈接;反之,若是客戶端收到了服務端發送的通過掩碼處理的數據包,也會自動斷開鏈接)。

掩碼處理:

未掩碼處理:

根據咱們的分析,服務端到客戶端數據包的websocket幀圖應該爲:

TCP KeepAlive

如上圖所示,TCP保活報文老是成對出現,包括TCP保活探測報文和TCP保活探測確認報文。
TCP保活探測報文是將以前TCP報文的確認序列號減1,並設置1個字節,內容爲「00」的應用層數據,以下圖所示:

TCP保活探測確認報文就是對保活探測報文的確認,其報文格式以下:

由於Websocket經過Tcp Socket方式工做,如今考慮一個問題,在一次長鏈接中,服務器怎麼知道消息的順序呢?這就涉及到tcp的序列號(Sequence Number)和確認號(Acknowledgment Number)。個人理解是序列號是發送的數據長度;確認號是接收的數據長度。這樣講比較抽象,咱們從TCP三次握手開始(結合下圖)詳細分析一下。

包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

相關文章
相關標籤/搜索