WebSocket 原理解析

各位大佬们,今天聊聊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: websocketConnection: 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

相关推荐
Lee川2 小时前
JavaScript 继承进化史:从原型链的迷雾到完美的寄生组合
前端·javascript·面试
米饭同学i2 小时前
微信小程序实现故事线指引动画效果
前端
阿懂在掘金2 小时前
为什么写 Vue 强烈建议用 Setup?除了复用,更是代码组织
前端·vue.js
sorryhc2 小时前
我让 AI 帮我写了一个 Code Agent!
前端·openai·ai编程
工边页字2 小时前
面试官:请详细介绍下AI中的token,越详细越好!
前端·人工智能·后端
anyup2 小时前
月销 8000+,uView Pro 让 uni-app 跨端开发提速 10 倍
前端·uni-app·开源
前端Hardy3 小时前
别再忽略 Promise 拒绝了!你的 Node.js 服务正在“静默自杀”
前端·javascript·面试
前端Hardy3 小时前
别再被setTimeout闭包坑了!90% 的人都写错过这个经典循环
前端·javascript·vue.js
小林coding3 小时前
专为程序员打造的简历模版来啦!覆盖前端、后端、测开、大模型等专业简历
前端·后端