websocket原理

4 阅读5分钟

一、WebSocket 是什么?解决了什么问题?

定义:WebSocket 是 HTML5 中定义的双向、全双工通信协议,基于 TCP 实现,允许客户端与服务器建立持久连接,数据可双向主动传输。

解决的痛点

  • HTTP 轮询的低效性:传统 Web 应用通过定时请求(如 AJAX 轮询)获取更新,存在“请求-响应” overhead 和实时性差的问题;
  • 单向通信限制:HTTP 协议中服务器无法主动向客户端推送数据,需客户端主动请求。

二、WebSocket 核心原理:握手与通信流程

1. 握手阶段(建立连接)

本质:基于 HTTP 协议完成 WebSocket 协议升级(Upgrade)。

// 客户端请求(WebSocket 握手)
GET /chat HTTP/1.1
Host: example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==  // 随机 Base64 字符串
Sec-WebSocket-Version: 13

// 服务器响应(握手成功)
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=  // 服务器对 Key 加密后的结果

关键点

  • 协议升级标志Upgrade: websocketConnection: Upgrade 告知服务器切换协议;
  • 密钥验证:服务器通过 Sec-WebSocket-Key 验证请求合法性,防止跨域攻击;
  • 状态码 101:表示协议切换成功,后续通信不再使用 HTTP 协议。
2. 数据传输阶段(全双工通信)

通信模型:建立在 TCP 连接上的双向数据流,客户端与服务器可随时主动发送数据。

帧结构(Frame)
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 ...                :  
+---------------------------------------------------------------+
  • 关键字段
    • opcode:标识帧类型(如文本帧 0x01、二进制帧 0x02、关闭连接帧 0x08);
    • mask:客户端发送的帧必须设置 mask=1,服务器无需(防止跨站点WebSocket劫持);
    • payload:实际传输的数据,支持分片(大文件可拆分为多个帧传输)。
3. 连接关闭阶段
  • 主动关闭:客户端或服务器可发送 关闭帧(opcode=0x08),携带状态码(如 1000 正常关闭、1006 异常断开)和可选原因;
  • 被动关闭:若连接超时、网络断开或收到非法帧,会触发异常关闭;
  • 状态码意义
    • 1000:正常关闭;
    • 1001:服务器/客户端离开(如浏览器关闭);
    • 1003:不支持的数据类型;
    • 1006:未收到关闭帧的异常断开(如网络中断)。

三、WebSocket 与 HTTP 的核心区别

维度HTTPWebSocket
连接性质短连接(请求-响应后关闭)长连接(一次握手后持续保持)
通信方向单向(客户端→服务器)双向(全双工)
协议层级应用层协议应用层协议(基于 TCP)
头部开销每次请求需携带完整头部握手后头部精简(仅包含帧信息)
数据格式文本为主(JSON/XML)支持文本/二进制,帧结构更高效
推送能力无(需客户端主动请求)支持服务器主动推送

四、问题

1. 问:WebSocket 如何实现心跳机制?有什么作用?

  • 实现方式
    1. 客户端定时发送 ping 帧(opcode=0x09);
    2. 服务器收到后回复 pong 帧(opcode=0x0A);
    3. 若客户端未在超时时间内收到 pong,判定连接断开并尝试重连。
  • 作用
    • 检测网络连接状态(防止长连接被中间节点(如路由器)断开);
    • 维持连接活跃性(避免被防火墙视为“死连接”而关闭)。
2. 问:WebSocket 如何处理断线重连?有哪些策略?

  • 重连策略
    1. 定时重连:断开后固定时间(如 5s)尝试重连;
    2. 指数退避重连:首次重连间隔 1s,失败后间隔翻倍(1s→2s→4s…),避免频繁重连占用资源;
    3. 最大重连次数:设置上限(如 10 次),超过则提示用户手动刷新。
  • 状态管理:重连时需记录未完成的消息,确保数据不丢失。
3. 问:WebSocket 如何解决跨域问题?

  • WebSocket 握手阶段通过 Origin 字段标识客户端来源,服务器可在响应头中通过 Sec-WebSocket-Origin 控制跨域:
    • 若允许跨域,服务器正常返回握手响应;
    • 若拒绝,返回 403 错误或不响应握手请求。
  • 与 HTTP 跨域不同,WebSocket 不依赖 Access-Control-Allow-Origin 头,而是在握手层自主控制。
4. 问:WebSocket 在海量连接场景下的性能瓶颈及优化?

  • 瓶颈
    • 服务器资源消耗(每个连接占用一个文件描述符,内存开销大);
    • 线程模型限制(传统线程池处理大量连接时上下文切换开销高)。
  • 优化方案
    1. 使用高性能 Web 服务器:如 Nginx 作为反向代理,Node.js 或 Go 语言处理 WebSocket(事件驱动模型);
    2. 连接分片与负载均衡:按用户 ID 哈希分配到不同服务器,避免单点压力;
    3. 心跳优化:对活跃连接和非活跃连接设置不同心跳间隔;
    4. 二进制传输:避免文本序列化开销,直接传输二进制数据(如 Protocol Buffers)。

五、总结

握手基于 HTTP 升级,全双工靠帧传输;
心跳防断连,重连讲策略,跨域看 Origin;
对比 HTTP 抓核心:长连接、双向通、低开销。