websocket封装

WebSocket 是一种基于 TCP 的通信协议,允许客户端与服务器之间建立一个持久的连接,进行双向实时通信。

1. WebSocket 构造函数

通过 new WebSocket(url) 创建 WebSocket 实例。

const ws = new WebSocket('ws://your-websocket-url');

2. WebSocket 主要方法

send(data)

用于向服务器发送数据。可以发送文本数据或二进制数据(如 Blob 或 ArrayBuffer)。注意:只有在连接成功后,readyStateOPEN 时才能发送数据。

ws.send('Hello, Server!');

close(code?, reason?)

用于关闭 WebSocket 连接。codereason 是可选参数:

  • code(可选):指定 WebSocket 连接关闭的状态码,默认是 1000,表示正常关闭。
  • reason(可选):指定一个关闭的原因,最大长度为 123 字符。
ws.close(1000, 'Normal closure');

3. WebSocket 主要属性

readyState

WebSocket 的状态,返回一个数字,表示连接的当前状态。它有 4 个可能的值:

  • 0CONNECTING - WebSocket 连接正在建立。
  • 1OPEN - WebSocket 连接已建立,可以进行通信。
  • 2CLOSING - WebSocket 正在关闭。
  • 3CLOSED - WebSocket 连接已经关闭或无法打开。

可以通过 ws.readyState 来查看当前 WebSocket 的状态。

bufferedAmount

返回当前 WebSocket 发送队列中的字节数。这可以帮助你了解缓冲区中还有多少数据等待发送。

 

4. WebSocket 事件

WebSocket 通过以下事件与客户端进行交互:

onopen: 当 WebSocket 连接成功建立时触发。可以在这里初始化与服务器的交互。

ws.onopen = function(event) {
  console.log('WebSocket is open now.');
};

onmessage: 当 WebSocket 接收到消息时触发。该事件处理程序的 event 对象的 data 属性包含了接收到的数据(字符串或二进制数据)。

ws.onmessage = function(event) {
  console.log('Received data: ', event.data);
};

onerror: 当 WebSocket 发生错误时触发。通常会在 WebSocket 连接发生故障或无法建立连接时触发。

ws.onerror = function(event) {
  console.error('WebSocket error:', event);
};

onclose: 当 WebSocket 连接关闭时触发。你可以在这里执行一些清理操作。

ws.onclose = function(event) {
  console.log('WebSocket closed', event.code, event.reason);
};

5. 带心跳检测和自动重连的websocket封装库

为了确保 WebSocket 连接保持活跃,可以定期发送“心跳”消息。如果服务器在一定时间内没有回应,可以视为连接断开,触发重连。

核心实现:

  • 客户端定期发送心跳请求(ping)
  • 服务器收到心跳请求后返回响应(pong)
  • 客户端在规定时间内未收到服务器的 pong 响应时,触发重连机制

使用 setInterval 来定时发送心跳消息。例如,每隔 30 秒向服务器发送一个“ping”消息。

当客户端收到服务器返回的 pong 消息时,清除现有的定时器并重新启动,以保证心跳机制持续有效。

class WebSocketWithHeartbeatAndReconnect {
  constructor(url, options = {}) {
    this.url = url;
    this.socket = null;
    this.heartbeatInterval = options.heartbeatInterval || 30000; // 默认每 30 秒发送一次心跳
    this.pingMessage = options.pingMessage || 'ping'; // 默认 ping 消息
    this.pongMessage = options.pongMessage || 'pong'; // 默认 pong 消息
    this.reconnectInterval = options.reconnectInterval || 5000; // 默认每 5 秒尝试重连
    this.maxReconnectAttempts = options.maxReconnectAttempts || 5; // 最大重连次数
    this.reconnectAttempts = 0; // 当前已尝试的重连次数
    this.heartbeatTimer = null; // 存储心跳定时器
    this.reconnectTimer = null; // 存储重连定时器
  }

  // 初始化 WebSocket 连接
  connect() {
    if (this.socket) {
      this.socket.close(); // 关闭现有连接
    }

    this.socket = new WebSocket(this.url);

    // 连接成功时启动心跳
    this.socket.onopen = () => {
      console.log('WebSocket connected');
      this.reconnectAttempts = 0; // 重置重连次数
      this.startHeartbeat(); // 启动心跳机制
    };

    // 接收到消息时
    this.socket.onmessage = (event) => {
      console.log('Received message:', event.data);

      // 如果接收到 pong 消息,说明服务器回应了心跳
      if (event.data === this.pongMessage) {
        console.log('Pong received');
        this.resetHeartbeat(); // 重置心跳定时器
      }
    };

    // 连接关闭时
    this.socket.onclose = (event) => {
      console.log('WebSocket closed:', event);
      this.stopHeartbeat(); // 停止心跳机制
      this.handleReconnect(); // 尝试重连
    };

    // 错误处理
    this.socket.onerror = (error) => {
      console.error('WebSocket error:', error);
      this.socket.close(); // 在发生错误时关闭连接
    };
  }

  // 启动心跳机制,定时发送 ping 消息
  startHeartbeat() {
    this.heartbeatTimer = setInterval(() => {
      if (this.socket && this.socket.readyState === WebSocket.OPEN) {
        console.log('Sending ping...');
        this.socket.send(this.pingMessage); // 发送 ping 消息
      }
    }, this.heartbeatInterval);
  }

  // 重置心跳机制
  resetHeartbeat() {
    clearInterval(this.heartbeatTimer); // 清除之前的心跳定时器
    this.startHeartbeat(); // 重新启动心跳定时器
  }

  // 停止心跳机制
  stopHeartbeat() {
    clearInterval(this.heartbeatTimer); // 清除心跳定时器
  }

  // 处理重连机制
  handleReconnect() {
    if (this.reconnectAttempts < this.maxReconnectAttempts) {
      this.reconnectAttempts++;
      console.log(`Attempting to reconnect... (${this.reconnectAttempts}/${this.maxReconnectAttempts})`);
      
      // 重连时延
      this.reconnectTimer = setTimeout(() => {
        this.connect(); // 尝试重新连接
      }, this.reconnectInterval);
    } else {
      console.log('Max reconnect attempts reached. Giving up.');
    }
  }

  // 发送数据
  send(message) {
    if (this.socket && this.socket.readyState === WebSocket.OPEN) {
      this.socket.send(message);
      console.log('Message sent:', message);
    } else {
      console.log('WebSocket is not open. Cannot send message.');
    }
  }

  // 关闭连接
  close() {
    if (this.socket) {
      this.socket.close();
      console.log('WebSocket closed manually.');
    }
  }
}

// 使用示例
const wsClient = new WebSocketWithHeartbeatAndReconnect('ws://your-websocket-url', {
  heartbeatInterval: 30000, // 每 30 秒发送心跳
  reconnectInterval: 5000,  // 每 5 秒尝试重连
  maxReconnectAttempts: 10, // 最大尝试 10 次
});

// 启动 WebSocket 连接
wsClient.connect();

// 发送数据
setTimeout(() => {
  wsClient.send('Hello WebSocket');
}, 5000);

// 关闭连接
setTimeout(() => {
  wsClient.close();
}, 20000);

  

  

posted @ 2025-02-07 17:00  我是格鲁特  阅读(286)  评论(0)    收藏  举报