WebSocket介紹

本文是對 WebSocket 變化的介紹,是對以下資料的摘錄:

WebSocket 概覽

WebSocket 是一個計算機間的通信協議,它能夠在單個 TCP 鏈接上構建一個雙工的交流通道。WebSocket 協議的標準是由 IETE 在 2011年的 RFC 6455 中制定的。

WebSocket 是一個與 HTTP 并不相同的 TCP 的協議。WebSocket 和 HTTP 協議都是在7層網絡模型(OSI model)中的,并且都依賴第4層的 TCP 協議。盡管兩者并不相同,但 RFC 6455 中聲明 “WebSocket 是可以工作在 HTTP協議 的80和443端口之上的,并且能夠支持 HTTP 代理和中介”,這使得 WebSocket 可以兼容 HTTP 協議。為了實現這個兼容目標,WebSocket 的握手(handshake)使用了 HTTP 的 Upgrade 頭部,從而實現從 HTTP 協議轉換為 WebSocket 協議的目標。

WebSocket 能夠建立客戶端和服務器間的雙向通信,目前很多瀏覽器都已經支持該協議了。同樣,服務端也需要提供相應的支持。

WebSocket 協議標志是 ws(WebSocket)和 wss(WebSocket Secure)。

協議標志

為什么需要 WebSocket

由于 HTTP 是客戶端發起的單向請求,對于聊天室這樣需要服務端推送信息的場景就不是很適合。當然,客戶端可以通過“輪詢”的方式來了解服務端的信息,但是這樣的效率比較低,比較浪費資源(因為必須不停連接,或者 HTTP 連接始終打開)。

和 HTTP 不同,WebSocket 是一個全雙工協議,屬于服務器推送技術的一種。在 WebSocket 之前,在80端口可以通過 Comet 通道實現全雙工。但是由于 TCP 握手和 HTTP 頭部的開銷,對于數據量不大的信息來說,這樣的機制不是很高效。WebSocket 協議的目標就是解決這些問題并且提供相應的安全保障。

握手協議

WebSocket 建立連接的過程如下:

  1. 客戶端發送 WebSocket 握手請求(和 HTTP 一樣, 每行要以 \r\n 結尾,最后要有一個額外的空行)。
GET /chat HTTP/1.1
Host: server.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==
Sec-WebSocket-Protocol: chat, superchat
Sec-WebSocket-Version: 13
Origin: http://example.com
  1. 服務端回應握手請求。
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk=
Sec-WebSocket-Protocol: chat

可以看到,客戶端發送的請求頭部除了 Upgrade 外,還有 Sec-WebSocket-Key 字段,它是包含base64編碼的隨機字節,服務端需要在 WebSocket-Accept 字段中返回這個鍵的hash值。這是為了防止緩存代理重發之前的 WebSocket 會話。

通過類 HTTP 形式的握手形式,可以使得服務端在同一個端口處理 HTTP 或者 WebSocket 協議。一旦 WebSocket 握手完成,通信馬上變換成一個與 HTTP 協議不同的雙向通道。


WebSocket協議過程

此外,從安全的角度來說,提供 Origin 標簽是很有必要的,可以避免跨站點的 WebSocket 劫持攻擊。

數據格式

全雙工的通道建立之后,傳輸的數據將會以盡可能小的格式進行封裝:一個小的頭部,緊跟著的是有效數據載體 payload。WebSocket 傳輸的內容被稱為“消息”,這個消息可以被劃分成多個數據幀。這樣在只有一部分初始數據(完整數據還未準備好)的時候就可以提前發送數據了。通過擴展,可以同時多路復用多個數據流(這樣可以避免大負載數據對 socket 的獨占使用)。

數據格式

FIN(1 bit)
表明消息是否是最后一幀。第一條消息也可能是最后一幀。

RSV1, RSV2, RSV3(每個都是1位)
必須是0,除非擴展定義了非0值的意義。如果收到非0值,并且沒有具體的定義,那么接收端必須使連接失敗。

Opcode(4位)
聲明 “Payload data” 的含義。如果收到一個未知編碼,那么接收端必須使連接失敗。目前有以下這些值:

  • %x0 denotes a continuation frame,表明是一個持續幀。
  • %x1 denotes a text frame,表明是一個文本幀。
  • %x2 denotes a binary frame,表明是一個二進制幀。
  • %x3-7 are reserved for further non-control frames,為未來的非控制幀保留。
  • %x8 denotes a connection close,定義一個連接結束。
  • %x9 denotes a ping,表示 ping 操作。
  • %xA denotes a pong,表示 pong 操作。
  • %xB-F are reserved for further control frames,為未來的控制幀保留。

__ Mask__(1 bit)
定義 “Payload data” 是否是隱秘的。如果設置為1,那么 masking-key 中會提供一個值,并且可以根據 5.3節 取消對應的標志。所有客戶端發送到服務端的幀都需要把這位設置為1。

Payload length(7位 或 7+16位 或 7+64位)
表示 “Payload data” 的長度。分為這幾種情況:

  • 如果是 0-125,那么就是實際長度。
  • 如果是 126,那么接下來的2個字節作為一個16位的無符號整數,表示實際的長度。
  • 如果是 127,那么接下來的8個字節作為一個64位的無符號整數,表示實際的長度。

其中多字節表示的長度在網絡中必須按序排列。值得注意的是,在所有例子中,長度必須按最短的表示方式表示。Payload 數據的長度是由 “Extension data” (擴展數據)和 “Extension data”(應用數據)組成的,當擴展數據的長度為0時,payload 數據的長度就是應用數據的長度。

Masking-key(0位或者4位)
所有從客戶端發送到服務端的數據幀都需要有一個32位的 Masking-key。當 mask 位被設置為1的時候,這個域存在;當 mask 位被設置為0的時候,這個域不存在。可以看 5.3節 來進一步了解。

Payload data(x+y位)
由 "Extension data"(擴展數據)和 "Application data"(應用數據)組成。

  • Extension data(x位):擴展數據默認是0位,除非實現了一個擴展協議。每一個擴展的協議必須說明擴展數據的長度、長度是如何計算的、以及在握手階段擴展是如何約定的。如果該部分數據存在,那么將會被記錄到總的 payload 長度中。
  • Application data(y位):應用數據在擴展數據之后,應用數據的長度等于 payload 的長度減去擴展數據的長度。
WebSocket 數據格式

其它資料

進一步了解可以參考這些文檔:

推薦一款非常特別的 WebSocket 服務器:Websocketd。它的最大特點,就是后臺腳本不限語言,標準輸入(stdin)就是 WebSocket 的輸入,標準輸出(stdout)就是 WebSocket 的輸出。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 一、內容概覽 WebSocket的出現,使得瀏覽器具備了實時雙向通信的能力。本文由淺入深,介紹了WebSocket...
    Calvin李閱讀 2,540評論 2 10
  • Spring Cloud為開發人員提供了快速構建分布式系統中一些常見模式的工具(例如配置管理,服務發現,斷路器,智...
    卡卡羅2017閱讀 134,881評論 18 139
  • 斷舍離與一般的整理收納術最大的區別就在于斷舍離并非絕對要把以房間弄干凈為目的,而是要通過收拾的過程了解并喜歡上真正...
    聆聽花開_5a8a閱讀 204評論 0 0
  • 生活中感覺一直在奔跑, 不得喘息, 前方的路卻變得越來越飄渺。 人變得麻木, 忘記了抬頭享受藍天艷陽, 人變的脆弱...
    春光碎夢閱讀 196評論 0 1
  • 本文轉自喵神的博客,原文鏈接 在涉及到一些數據結構的經典理論和模型 (沒錯,就是鏈表,樹和圖) 時,我們往往會用到...
    小白猿閱讀 534評論 0 0