WebSocket 心跳机制

通过心跳保持 WebSocket 连接活跃并检测连接状态

问题

WebSocket 中的心跳机制是为了解决什么问题?

解答

WebSocket 心跳机制主要解决两个问题:

1. 防止连接超时断开

服务端通常会设置连接超时时间,如果长时间没有数据传输,连接会被自动断开。通过定时发送心跳消息,可以让服务端知道连接仍然活跃,避免超时断线。

2. 检测连接健康状态

在连接看似正常的情况下,服务端可能已经出现异常。通过心跳机制可以及时发现问题:

  • 客户端定时发送心跳包(ping)
  • 服务端收到后返回响应(pong)
  • 如果在规定时间内没有收到响应,说明连接异常,需要重连

实现示例

class WebSocketClient {
  constructor(url) {
    this.url = url;
    this.ws = null;
    this.heartbeatInterval = 30000; // 30秒
    this.heartbeatTimer = null;
    this.reconnectTimer = null;
    this.pongTimeout = 5000; // 等待pong响应的超时时间
    this.pongTimer = null;
  }

  connect() {
    this.ws = new WebSocket(this.url);
    
    this.ws.onopen = () => {
      console.log('连接成功');
      this.startHeartbeat();
    };

    this.ws.onmessage = (event) => {
      if (event.data === 'pong') {
        clearTimeout(this.pongTimer);
      }
      // 处理其他消息
    };

    this.ws.onclose = () => {
      console.log('连接断开');
      this.stopHeartbeat();
      this.reconnect();
    };

    this.ws.onerror = (error) => {
      console.error('连接错误', error);
    };
  }

  startHeartbeat() {
    this.heartbeatTimer = setInterval(() => {
      if (this.ws.readyState === WebSocket.OPEN) {
        this.ws.send('ping');
        
        // 设置pong响应超时
        this.pongTimer = setTimeout(() => {
          console.log('心跳超时,重连');
          this.ws.close();
        }, this.pongTimeout);
      }
    }, this.heartbeatInterval);
  }

  stopHeartbeat() {
    if (this.heartbeatTimer) {
      clearInterval(this.heartbeatTimer);
      this.heartbeatTimer = null;
    }
    if (this.pongTimer) {
      clearTimeout(this.pongTimer);
      this.pongTimer = null;
    }
  }

  reconnect() {
    this.reconnectTimer = setTimeout(() => {
      console.log('尝试重连');
      this.connect();
    }, 3000);
  }

  close() {
    this.stopHeartbeat();
    if (this.reconnectTimer) {
      clearTimeout(this.reconnectTimer);
    }
    if (this.ws) {
      this.ws.close();
    }
  }
}

// 使用
const client = new WebSocketClient('ws://localhost:8080');
client.connect();

关键点

  • 心跳机制通过定时发送消息防止连接因超时被服务端断开
  • 通过 ping-pong 模式检测连接是否真正可用,而不仅仅是表面连接
  • 如果在规定时间内未收到 pong 响应,应主动断开并重连
  • 心跳间隔要小于服务端的超时时间,通常设置为超时时间的一半
  • 断线重连时要清理所有定时器,避免内存泄漏