WebSocket

WebSocket 是一种基于 TCP 的全双工通信协议,允许服务端主动向客户端推送数据。

与 HTTP 协议的区别

  1. 连接方式:HTTP 是短连接(无状态),WebSocket 是长连接。
  2. 通信模式:HTTP 只能客户端发起请求,WebSocket 支持双向实时通信。
  3. 协议头:WebSocket 通过 ws:// 或 wss://(加密)建立连接,握手阶段使用 HTTP 协议(状态码 101)。

WebSocket 的优点 / 缺点

优点

  1. 双向通信:WebSocket 提供了全双工通信机制,服务器和客户端可以在任何时刻发送数据给对方,适合需要实时数据交换的应用,如在线游戏、实时聊天等。
  2. 更低的延迟:一旦 WebSocket 连接建立,数据可以快速地在客户端和服务器之间传输,减少了 HTTP 每次请求都需要建立连接的开销。
  3. 减少通信量:WebSocket 在建立连接后,数据交换不需要每次都包含 HTTP 的头部信息,减少了额外的网络负载。
  4. 保持连接状态:WebSocket 通过一个持久的连接,可以更容易地管理和保持客户端和服务器之间的状态。

缺点

  1. 兼容性和支持:虽然现代浏览器都支持 WebSocket,但在一些旧的浏览器或网络设备中可能不被支持。
  2. 安全性:WebSocket 可能会增加安全风险,因为它保持了一个持久的连接。需要实现额外的安全措施,如使用 WSS(WebSocket Secure 即 WebSocket 协议的加密版本)。
  3. 复杂性:相对于简单的 HTTP 请求/响应模型,WebSocket 的实现和调试可能更复杂,特别是在处理大规模、高并发的连接时。
  4. 服务器资源:WebSocket 连接是持久的,相比于 HTTP 的无状态连接,它可能会占用更多的服务器资源。

心跳检测

定时发送 ping/pong 帧检测连接活性。

setInterval(() => {
    if (socket.readyState === WebSocket.OPEN) {
        socket.send('ping');
    }
}, 30000);

如果心跳检测不正常,那么尝试重新发起 WebSocket 连接(超过一定次数后提示用户手动刷新网页之类的操作重连)。

WebSocket 握手过程

  1. 客户端发送 HTTP 请求,包含 Upgrade: websocket 和 Sec-WebSocket-Key。
  2. 服务器返回状态码 101,包含 Sec-WebSocket-Accept(由客户端 Key 计算生成)。

WebSocket 性能优化

  1. 数据压缩(如使用 permessage-deflate 扩展)。
  2. 分片传输大数据,避免阻塞。
  3. 合理设计消息格式(如 JSON 或二进制协议)。

实现一个带重连机制的 WebSocket 客户端

class AutoReconnectWebSocket {
  constructor(url) {
    this.url = url;
    this.socket = null;
    this.reconnectInterval = 1000;
    this.connect();
  }
 
  connect() {
    this.socket = new WebSocket(this.url);
 
    this.socket.onopen = () => {
      console.log('Connected');
      this.reconnectInterval = 1000; // 重置重连间隔
    };
 
    this.socket.onclose = (e) => {
      console.log(`断开连接,${e.reason}`);
      setTimeout(() => this.connect(), this.reconnectInterval);
      this.reconnectInterval *= 2; // 指数退避
    };
 
    this.socket.onerror = (err) => {
      console.error('WebSocket 错误:', err);
      this.socket.close();
    };
  }
 
  send(data) {
    if (this.socket.readyState === WebSocket.OPEN) {
      this.socket.send(data);
    }
  }
}