各位大佬们,今天聊聊WebSocket。
WebSocket 是一种在单个 TCP 连接上进行全双工通信的协议,它使得客户端和服务器之间可以进行实时、双向的数据传输。与传统的 HTTP 请求-响应模式不同,WebSocket 允许服务器主动向客户端推送数据,从而大大降低了延迟和网络开销。本文将深入解析 WebSocket 的工作原理,包括握手过程、数据帧格式、心跳机制以及安全性等方面。
1.怎么了解它?
你可以把传统的 HTTP 通信想象成打电话:你给客服打电话(发请求),客服接起来回答你(响应),然后挂断。下一次你再有事,得重新拨号。这有个问题:如果客服想主动告诉你点啥,没门儿,只能等你再打过去。
而 WebSocket 呢,更像是一个对讲机:你和对方先约好频道,然后一直开着,你随时可以说话,对方也随时可以说话,不用每次都重新连接。这就是"全双工"------两边都能同时说。
2.怎么建立连接?
其实一开始还是要用 HTTP 来"握手"。
客户端(比如你的浏览器)对服务器说:"嘿,我想升级成 WebSocket 聊天,这是我的密钥(Sec-WebSocket-Key),你看行不行?"
服务器收到后,拿着这个密钥和一把固定的"魔法钥匙"(GUID)一组合,算出一个值,然后回复:"OK,切换协议(101 Switching Protocols),这是我的凭证(Sec-WebSocket-Accept),以后咱就用新规则聊天吧。"
之后,这个 TCP 连接就变成了一条专用通道,两边随时可以互发消息。
3. WebSocket 与 HTTP 的关系
WebSocket 协议在设计上兼容 HTTP,它使用 HTTP 的 80 和 443 端口,并通过 HTTP 升级机制来建立连接。因此,WebSocket 握手阶段使用 HTTP 协议,之后则切换到 WebSocket 协议进行数据传输。这种设计使得 WebSocket 可以轻松地穿越防火墙和代理服务器。
主要区别:
- 通信模式:HTTP 是半双工(客户端请求,服务器响应),WebSocket 是全双工(双方可随时发送数据)。
- 协议开销:HTTP 每次请求/响应都包含头部信息,开销较大;WebSocket 建立连接后,头部开销很小(仅 2-14 字节)。
- 实时性:HTTP 需要轮询才能实现近似实时,WebSocket 则提供真正的实时推送。
4. WebSocket 握手过程
WebSocket 连接的建立始于一个 HTTP 请求,该请求包含特定的头部字段,表明客户端希望将协议升级到 WebSocket。
客户端握手请求示例:
text
makefile
GET /chat HTTP/1.1
Host: server.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Sec-WebSocket-Version: 13
Origin: http://example.com
关键字段说明:
Upgrade: websocket和Connection: Upgrade:告知服务器要升级协议到 WebSocket。Sec-WebSocket-Key:一个随机生成的 16 字节值经过 Base64 编码,用于防止缓存代理服务器误将后续通信视为 HTTP。Sec-WebSocket-Version:协议版本号,目前为 13。Origin:用于防止未授权的跨域请求(类似 CORS)。
服务器握手响应示例:
text
makefile
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
服务器收到请求后,计算 Sec-WebSocket-Key 与固定 GUID(258EAFA5-E914-47DA-95CA-C5AB0DC85B11)拼接后的 SHA1 哈希,再进行 Base64 编码,得到 Sec-WebSocket-Accept。客户端验证此值以确保握手成功。
响应状态码 101 表示协议切换成功,之后 TCP 连接保持打开,进入全双工通信阶段。
5. WebSocket 数据帧格式
WebSocket 使用自定义的帧格式来传输数据,每个帧包含一个固定头部(2-14 字节)和可选的负载数据。帧格式设计考虑了效率和控制,支持分片、掩码(客户端到服务器的数据必须掩码)等功能。
帧结构(RFC 6455):
text
lua
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:是否为消息的最后一个分片。
-
opcode:表示帧类型。
0x0:延续帧(分片中的后续帧)0x1:文本帧(UTF-8 数据)0x2:二进制帧0x8:关闭连接帧0x9:Ping 帧0xA:Pong 帧
-
MASK:掩码标志。客户端发送的数据必须设为 1,并附带 32 位的 masking-key;服务器发送的数据必须设为 0。
-
Payload length:负载长度。如果为 126,则后续 2 字节表示实际长度;如果为 127,则后续 8 字节表示实际长度。
-
Masking-key:用于解码负载的 32 位密钥(仅当 MASK=1 时存在)。
掩码机制用于防止早期协议缓存污染攻击,确保代理服务器不会误解数据。
6. 心跳机制:Ping/Pong 帧
WebSocket 提供了 Ping 和 Pong 帧来实现连接保活(心跳)。一方可以发送 Ping 帧,另一方必须回应 Pong 帧(携带相同的数据)。这有助于检测连接是否意外中断,并维持中间网络设备(如 NAT)的会话状态。
Ping/Pong 帧的 opcode 分别为 0x9 和 0xA,负载数据可选(但通常为空)。
7. 安全性:WSS
WebSocket 支持安全传输,即 WebSocket over TLS,通常称为 WSS(WebSocket Secure)。与 HTTPS 类似,WSS 使用 wss:// 协议标识,连接建立在 TLS 之上,确保数据的机密性和完整性。WSS 的握手也是通过 HTTP over TLS 进行的(即 HTTPS 升级),然后切换到加密的 WebSocket 通信。
使用 WSS 可以有效防止中间人攻击和数据窃听,尤其对于生产环境至关重要。
8. 应用场景
WebSocket 的实时双向通信特性使其广泛应用于以下场景:
- 即时聊天/消息推送:如微信网页版、在线客服。
- 实时数据更新:股票行情、体育比分、物联网设备状态。
- 协作应用:在线文档编辑、白板共享。
- 多人在线游戏:实时对战、状态同步。
- 直播弹幕:观众与主播实时互动。
9. 总结
WebSocket 协议通过一次 HTTP 升级握手,建立起一个持久、全双工的 TCP 连接,极大地简化了实时 Web 应用的开发。其轻量级的帧格式、内置的心跳机制以及基于 TLS 的安全扩展,使得它成为现代 Web 实时通信的标准方案。理解 WebSocket 的工作原理,有助于我们更好地设计高实时性、低延迟的网络应用。
参考资料:RFC 6455 - The WebSocket Protocol