Websocket 使浏覽器具有實時的雙向通信能力。它可以打開使用者浏覽器和伺服器之間的互動式通信會話。它提供了一種通過持久連接配接在用戶端和伺服器之間交換資料的方法。
首先我們要明白,WebSocket本質上是一個計算機網絡應用層的協定,用來彌補HTTP協定持久通信能力的不足。
HTTP 協定是一種無狀态協定。每個新的 HTTP 請求隻能由用戶端發起。每個 HTTP 請求都已完全結束。雖然HTTP1.1增加了keep-alive請求頭,可以通過一個channel進行多次請求,但本質還是一樣的。
建立連接配接->傳輸資料->傳輸後斷開
WebSocket 是 TCP 傳輸協定,複用 HTTP 握手通道。可實作全雙工和長連接配接通信。可以在單個 TCP 連接配接上進行全雙工通信,可以更好地節省伺服器資源和帶寬,實作實時通信。用戶端和伺服器隻需完成一次握手,兩者之間就可以建立持久連接配接。
WebSocket 是一種基于 TCP/IP 協定、獨立于 HTTP 協定的通信協定。
HTTP 協定本身并沒有持久的通信能力,但是我們在實際應用中需要這種能力。WebSocket 解決了 HTTP 的這些問題。當服務端完成從 HTTP 到 WebSocket 的協定更新後,服務端可以主動向用戶端推送資訊。2011年被網際網路工程任務組(IETF)指定為标準RFC6455 ,并更新為RFC7936 . 于是,在HTML5标準中加入了WebSocket協定的相關API,隻要實作了HTML5标準的用戶端,就可以與支援WebSocket協定的伺服器進行全雙工持久通信。由于 WebSocket 隻需要一次 HTTP 握手,伺服器可以一直與用戶端通信,直到連接配接關閉,解決了伺服器重複解析 HTTP 協定的需要,減少了資源開銷。
WebSocket 的特點
- 2路通訊
- 有狀态的
- 可以在浏覽器中使用
WebSocket協定原理
WebSocket 協定需要建立 TCP 連接配接來傳輸資料。具體實作是通過HTTP協定建立通道,然後使用WebSocket協定進行通信,是以WebSocket協定和HTTP協定有一定的交叉關系。
WebSocket 協定端口 = 80
WebSocket SSL 協定端口 = 443
Handshake WebSocket 也有一個握手過程,然後就可以正式發送和接收資料了。用戶端發送的資料格式如下:
- 用戶端請求消息
用戶端發起 WebSocket 協定請求。
GET /chat HTTP/1.1
Upgrade: websocket
Connection: Upgrade
Host: server.example.com
Origin: http://example.com
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Sec-WebSocket-Protocol: chat, superchat
Sec-WebSocket-Version: 13
與傳統 HTTP 消息的差別:
Upgrade: websocket
Connection: Upgrade
這兩行表示 WebSocket 協定已啟動。
Sec-WebSocket-Key:dGhlIHNhbXBsZSBub25jZQ==
Sec-WebSocket-Version:13
Sec-WebSocket-Key它由浏覽器随機生成,并針對惡意或無意的連接配接提供基本保護(Base64 編碼值)。
Sec-WebSocket-Version表示 WebSocket 的版本。最初WebSocket協定太多,不同廠商有自己的協定版本,現在已經确定了。如果伺服器不支援該版本,則需要傳回一個Sec-WebSocket-Versionheader,其中包含伺服器支援的版本号。
建立一個 WebSocket 對象:
var ws = new websocket("ws://127.0.0.1:8001");
ws表示使用WebSocket協定,後面是位址和端口
2. 伺服器響應消息
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
Sec-WebSocket-Protocol: chat
- 101狀态碼表示伺服器已經了解了用戶端的請求,會通過Upgrade消息頭通知用戶端使用不同的協定來完成請求
- 101 Switching Protocols顯示HTTP請求完成後響應的狀态碼,表示協定已經切換,表示WebSocket協定通過HTTP協定建立傳輸層的TCP連接配接,然後與HTTP協定無關.
- Sec-WebSocket-Accept由伺服器确認并加密Sec-WebSocket-Key
- Sec-WebSocket-Protocol代表最終使用的協定
-
Sec-WebSocket-Accept
計算方法:将Sec-WebSocket-Key請求頭中的值添加到專用UUID。摘要由 SHA1 計算并轉換為 base64 字元串。
- Sec-WebSocket-Key/的轉換Sec-WebSocket-Accept隻能帶來基本的保證,但是連接配接是否安全,資料是否安全,用戶端/伺服器是否合法,ws用戶端,ws伺服器,都沒有實際的保證。
WebSocket 資料幀
- WebSocket 以幀為機關傳輸資料。幀是用戶端和伺服器之間資料傳輸的最小機關。
- 當資料過大時,可以将消息拆分成多幀發送。
- 解碼是恢複完整的消息
幀頭中的操作碼字段
- FIN,長度為 1 位,該标志用于訓示目前幀是消息的最後一段。FIN字段全部為0,最後一幀的FIN字段為1。如果消息沒有被分段,那麼一幀包含完整的消息,它的FIN字段值為1。
- RSV 1~3 — 這 3 個字段是保留字段,僅在 WebSocket 擴充中使用。如果接收方接收到 RSV 1~3 不全為 0 的幀,則這 3 個字段應設定為 1。 2 方尚未協商使用 WebSocket 協定擴充,接收方應立即終止 WebSocket 連接配接
- Opcode,長度為4位,該字段将訓示幀的類型
- 0x0 — 延續幀
- 0x1 — 文本框
- 0x2 — 二進制幀
- 0x3~7,目前保留,以後會作為更多的非控制幀使用
- 0x8——連接配接關閉
- 0x9 — 目前 ping 幀
- 0xA — 目前的乒乓幀
- 0xB ~F——目前保留,未來将用作更多控制幀
- Mask,長度為1位,該字段為标志位,用于訓示該幀的資料(有效載荷)是否被屏蔽。
- Payload Len — 幀有效載荷的長度(以位元組為機關),該字段的長度是可變的,可能是 7 位,可能是 7+16 位,也可能是 7+64 位。
- Masking-key — 當 Mask 标志為 1 時,表示這是一個被掩碼覆寫的幀。此時存在Masking-key字段,長度為32位。發送到伺服器的幀必須用掩碼覆寫。該字段的值由用戶端使用具有足夠大熵值的随機數生成器生成。
- Payload——這個字段的長度是任意的,這個字段是幀的資料部分。
WebSocket 控制類架構
主要用于傳遞一些連接配接控制資訊
- 關閉架構——用于關閉 WebSocket 連接配接
- Ping Frame——檢測幀,主要用于實作WebSocket層的Keep-Alive,或者檢測對方是否還處于活躍狀态
- Pong Frame — 是 Ping Frame 的響應,一方面,接收方在收到 Ping 幀後應立即發回 Pong Frame,并且 Payload 的内容必須與 Ping 幀相同。
狀态碼
連接配接成功狀态碼
101 - HTTP 協定切換到 WebSocket 協定
連接配接關閉狀态碼
1000:正常斷開
1001:伺服器斷開連接配接
1002:WebSocket 協定錯誤
103:用戶端接受不支援的資料格式
1006:異常關機
1007:用戶端接受了無效的資料格式(短信編碼不是utf-8)
1009:傳輸資料量太大
1010:用戶端終止連接配接
1011:伺服器終止連接配接
1012:伺服器正在重新啟動
1013:伺服器暫時終止
1014:通過網關或代理向伺服器請求,伺服器無法及時響應
1015:TLS 握手失敗
WebSocket斷線的原因
- 網絡狀态不好
- 資料被各種類型(路由器、防火牆、代理伺服器)阻止
- 網絡伺服器故障
WebSocket斷開連接配接的解決方案
- Heartbeat Reconnection — 它是通過 ping/pong(正常幀/控制幀)的伺服器端實作來實作的。伺服器向用戶端發送ping 0x9 消息,用戶端自動傳回pong 0xA 消息。用戶端定期向伺服器發送消息。這裡的消息是指WebSocket協定的資料幀,不需要通過代碼實作。不同用戶端發送消息的時間間隔不同。
優勢
- 更少的控制開銷——資料標頭協定更小,不像 HTTP 為每個請求攜帶一個完整的頭
- 更強的實時性——相比HTTP請求需要等待用戶端發起請求,服務端可以響應,延遲明顯更小
- 保持連接配接狀态——通信建立後,可以省略狀态資訊。
- 更好的二進制支援——定義了二進制幀,更好地處理二進制内容
- 支援擴充——使用者可以擴充WebSocket協定,實作一些自定義的子協定
- 更好的壓縮——WebSocket可以繼續使用之前内容的上下文,可以顯着提高壓縮比
如果你發現我的任何文章有幫助或有用,麻煩點贊或者轉發。 謝謝!