WebSocket 協議 - 概念原理
Part1WebSocket 是什麼
WebSocket 是一種網絡傳輸協議,可以在單個 TCP 連接上進行全雙工通信,它位於 OSI 模型的應用層。
WebSocket 與 HTTP 不是同一種協議,雖然兩者都位於 OSI 模型的應用層,並且都依賴底層的 TCP 協議。它們有着各自的協議格式,應用不同的場景。WebSocket 協議本身不依賴於 HTTP 協議,但是在 WebSocket 最初的建立階段依賴於 HTTP,因爲在 WebSocket 的握手過程使用了 HTTP 請求來升級協議。
WebSocket 協議 URL 與 HTTP 類似,明文協議 scheme 爲 ws:, 對應到 HTTP 協議是 http:。基於 SSL/TLS 的 WebSocket 協議的 scheme 爲 wss:, 對應到 HTTP 協議是 https:。ws 默認端口爲 80,wss 默認端口爲 443。
Part2 爲什麼需要 WebSocket
web 通信已經有了 HTTP 協議,爲啥還要搞一個 WebSocket 協議呢?一定是 HTTP 協議不能滿足某些場景下的需求。下面先分析 HTTP 協議存在問題,然後分析 WebSocket 是如何工作的。
1 HTTP 協議
HTTP 是請求應答通信模型,即客戶端主動向服務器發送 Request 請求,服務器回覆 Response 數據。服務器無法主動地向客戶端發送資源,所以 HTTP 協議下客戶端和服務器之間是非對稱工作方式,是一種半雙工通信。
當客戶端向服務器發送一個 HTTP 請求時,客戶端和服務器之間打開一個 TCP 連接,並且在接收到響應後,這個 TCP 連接會被終止。每個 HTTP 請求都會向服務器打開一個單獨的 TCP 連接,如果客戶端向服務器發送了 10 個請求,就會打開 10 個獨立的 TCP 連接。
HTTP 協議存在如下問題:
-
實時性差:通過前面 HTTP 協議介紹可以看到,HTTP 採用的是請求應答模型,服務器無法主動向客戶端發送消息。無法滿足一些應用場景需求,像在線遊戲、實時數據更新。如果採用 HTTP 協議實現,需要通過輪詢來實現,及時性很差。
-
性能不高:每次請求都會打開 TCP 連接,請求應答後連接關閉,在頻繁通信的場景下,這種頻繁 TCP 建立連接和關閉連接,很消耗性能。
所以引入 WebSocket 協議解決 HTTP 存在的問題。
2 WebSocket 協議
WebSocket 協議交互過程如下圖,整個過程分爲兩個階段。階段 1:進行握手。階段 2:進行數據傳輸。
握手
出於兼容性考量,握手採用 HTTP 來實現。客戶端發送的握手消息是一個帶有 Upgrade 頭的 HTTP Request 消息。具體長下面這樣。
GET /chat HTTP/1.1
Host: server.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Origin: http://example.com
Sec-WebSocket-Protocol: chat, superchat
Sec-WebSocket-Version: 13
-
通過 GET 發送 HTTP 請求,需要 HTTP 版本號 >=1.1
-
Host: 主機名,用於客戶端和服務端都能驗證它們是否使用的是同一個主機
-
Upgrade: 升級到 WebSocket 協議
-
Connection: 連接類型應該被升級,通常與 Upgrade 一起使用
-
Sec-WebSocket-Key:隨機生成的 16 字節內容,然後通過 Base64 編碼。確保服務端能夠正確地響應客戶端的請求,從而驗證服務端的身份
-
Sec-WebSocket-Protocol:指定使用哪個協議
-
Sec-WebSocket-Version:客戶端可以接受哪些子協議
服務端回覆給客戶端的報文如下。
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
Sec-WebSocket-Protocol: chat
-
101: 服務端響應 101 狀態碼,任何非 101 狀態碼都會導致錯誤,意味着 WebSocket 握手未完成
-
Sec-WebSocket-Accept:將客戶端傳過來的 Sec-WebSocket-Key 和全局唯一標識符組合後的 Base64 編碼哈希值。
如果 Sec-WebSocket-Accept 的值與預期值不匹配,缺少頭字段或者 HTTP 狀態碼不是 101,那麼連接將不會被建立,也不會發送數據幀。
發送數據
WebSocket 數據幀格式如下:
-
FIN: 佔 1 個 bit,標記這個幀是不是消息中的最後一個幀,第一個幀也可以是最後一個幀。因爲在 WebSocket 通信中,一個完整的消息可能需要分成多個幀來傳輸,而 FIN 字段就用來告訴對方是否還有後續的幀。
-
RSV1/RSV2/RSV3: 各佔 1 個 bit, 值必須是 0。
-
opcode: 操作碼,佔 4 個 bit, 表示數據載荷 payload data 類型,詳情見下表。
-
MASK: 掩碼標識,佔 1 個 bit。表示載荷數據 payload data 是否被掩碼。如果設置爲 1,Masking-key 部分有一個掩碼鑰匙,用這個鑰匙對載荷數據進行掩碼操作。
-
Payload len: 數據長度,佔用 7/(7+16)/(7+64)個 bit 位。如果值在 0-125 之間,則該值大小就表示數據長度。如果值爲 126,則接下來的兩個字節(16bit) 表示的 16 位無符號整數即爲數據長度。如果值爲 127,則接下來八個字節(64bit) 表示的 64 位無符號整數即爲數據長度。
-
Masking key: 掩碼鑰匙,佔用 0 或 4 個字節,所有客戶端發送到服務端的數據必須使用一個 32 位值進行掩碼。
-
Payload data: 應用數據。
Part3 WebSocket 使用場景
1 實時 Web 應用程序
實時 Web 應用程序使用 WebSocket 連接來展示服務器發送的數據。例如,在交易網站或股票交易中,價格總是波動,向客戶端展示價格時延遲要儘可能小。
2 遊戲應用程序
在遊戲應用程序中,客戶端持續向服務器發送數據,然後服務器在不刷新用戶界面的情況下將數據發送回客戶端。
3 聊天應用程序
大多數聊天應用程序使用 WebSocket 提供用戶之間不間斷和快速的通信渠道。
4 實時協作編輯
像各種雲文檔,例如騰訊文檔、石墨文檔等。
5 實時數據可視化
前端可以通過 WebSocket 通道從後端獲取數據,自動更新數據圖表,如條形圖、餅圖等。在數據統計分析、數字化大屏領域用的很多。
6 實時定位應用
移動應用中實時共享位置更新。
7 語音識別應用
語音識別,實時返回識別後的文字。
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/osM4z6HC3X3aWIEO-jiTeA