WebSocket備忘
記些websocket的知識備忘。
對比HTTP優勢
websocket與HTTP一樣,都是建立TCP之上的應用層協議,它較於HTTP的優點主要有以下兩點:
- 全雙工
HTTP不允許服務端主動向client發送數據,websocket在設計之初着重考慮了這個問題,所以websocket支持全雙工通信,服務端可以主動給客戶端推送消息
- 傳輸更有效率
- HTTP經常需要建立TCP連接(keep-alive可以部分解決),而websocket始終使用一個TCP來保持通信,在傳輸數據的過程中可以節省建立TCP連接的費時,以及避免TCP慢啓動對速度的影響
- 基於消息分幀且支持二進制的數據傳輸,在很多情景下相較於HTTP有效率優勢
連接建立過程
websocket作爲HTTP不能主動推送的替代方案,其連接建立過程卻依賴HTTP完成,主要原因是爲了與現有HTTP基礎設施兼容。使用HTTP建立連接可以複用80和443端口,因爲這兩個端口是被認可的,不太可能出現被中間設備或服務器防火牆攔截的情況。
通過HTTP建立連接的好處除了複用端口外,可以重用HTTP的Upgrade流,並擴展HTTP頭部字段完成建立連接的信息協商。
握手過程
建立連接的握手過程主要是以下兩步:
- 客戶端發出一個HTTP請求並攜帶Connection、Upgrade等頭部,與此同時還攜帶了一些擴展頭部如Sec-WebSocket-Key、Sec-WebSocket-Protocol等
- 服務端收到請求,如果支持websocket協議則返回狀態碼101表示切換協議,並且返回與客戶端一致Connection、Upgrade頭部外加部分與websocket連接建立有關的擴展頭部
當上訴握手步驟成功完成後,表明websocket連接建立完成,接下來的數據通信開始由websocket協議接管。
擴展頭部
部分擴展頭部的含義如下:
- Sec-WebSocket-Key
客戶端利用該頭部攜帶一次性的值來驗證接收到的請求服務器是否支持websocket協議,假設某代理緩存了一次握手請求的響應,當另一個client再次請求握手時,該代理沒有再次請求服務器而返回了上一個請求的響應,這時客戶端能判斷出當前鏈路不支持websocket協議,從而關閉連接
- Sec-WebSocket-Accept
響應頭,用於配合Sec-WebSocket-Key,服務器對client傳過來的Key進行簽名(配合一個全球唯一的GUID),再使用該頭部攜帶傳給客戶端表明支持websocket協議
- Sec-WebSocket-Protocol
用於商議websocket通信的子協議,具體規則是client通過該頭部提供一個備選列表,服務器從中選擇自己支持的一個傳回給client
數據幀
websocket協議通信的數據幀的結構如下:
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-------+-+-------------+-------------------------------+
|F|R|R|R| opcode|M| Payload len | Extended payload length |
|I|S|S|S| (4) |A| (7) | (16/64) |
|N|V|V|V| |S| | (if payload len==126/127) |
| |1|2|3| |K| | |
+-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - +
| Extended payload length continued, if payload len == 127 |
+ - - - - - - - - - - - - - - - +-------------------------------+
| |Masking-key, if MASK set to 1 |
+-------------------------------+-------------------------------+
| Masking-key (continued) | Payload Data |
+-------------------------------- - - - - - - - - - - - - - - - +
: Payload Data continued ... :
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
| Payload Data continued ... |
+---------------------------------------------------------------+
幀結構說明:
- FIN,表示當前幀是不是消息的最後一幀,因爲websocket協議的通信單位是“消息”,對於過長的消息有可能被分爲多個幀
- RSV1-3,擴展用途
- opcode,表示被傳輸幀的類型,一共這幾種:文本(1),二進制(2),關閉(8),ping(9),pong(10)
- MASK,表示Payload Data是否有掩碼,只適用客戶端發送給服務端的消息
- Extended payload length,表示Payload Data的長度,有多種可能:
- 0-255,就是Payload Data的長度
- 126,接下來的2字節所表示無符號整數纔是Payload Data的長度
- 127,接下來的8字節所表示無符號整數纔是Payload Data的長度
- Masking-key,掩碼的值
掩碼的作用可以防止惡意腳本擁有tcp socket權限,避免攻擊中間設備的可能,具體可以參考這篇文章
- Payload Data,淨荷,也就是被幀所攜帶的數據