分享一份关于websocket心跳的源码

看到最近有人迷上了云控/群控/中控,其中关键的通信协议websocket,却不知道怎么实现心跳。

在现代的Web开发中,WebSocket已成为一种重要的通信协议,它允许客户端和服务器之间进行全双工的通信,从而实现实时数据传输。

为了更好地利用WebSocket,在本文中我将分享一个我封装的 WebSocketClient 的JavaScript类的源码,并对其实现的功能进行详细讲解。

WebSocketClient源码

/**
 * WebSocket 客户端类,用于封装 WebSocket 连接和消息处理逻辑
 */
var WebSocketClient = /** @class */ (function () {
  /**
   * 构造函数,初始化 WebSocketClient 实例
   * @param webSocketUrl WebSocket 的 URL
   */
  function WebSocketClient(webSocketUrl) {
    this.webSocketUrl = webSocketUrl; // 存储 WebSocket 的 URL
    this.webSocket = null; // WebSocket 对象
    this.heartbeatInterval = null; // 心跳定时器
    this.reconnectTimer = null; // 重连定时器
    this.heartbeatResponseTimer = null; // 心跳回复计时器
    this.disconnect = false; // 是否主动断开连接
    this.isReconnecting = false; // 是否正在尝试重连
    this.onMessage = null; // 消息接收回调函数
    this.connectWebSocket(); // 初始化时即连接 WebSocket
  }
  WebSocketClient.prototype.initWs = function () {
    var _this = this;
    // WebSocket 连接成功
    this.webSocket.on("open", function (res, ws) {
      console.log("WebSocket 连接已建立");
      _this.sendHeartbeat(); // 发送心跳包
      _this.startHeartbeatTimer(); // 开启心跳定时器
      console.log("成功进入会话消息接收状态,onopen...");
    });
    // WebSocket 连接失败
    this.webSocket.on("failure", function (err, res, ws) {
      console.log("WebSocket连接失败");
      console.error(err);
      _this.reconnectWebSocket(); // 连接失败时触发重连
    });
    // WebSocket 正在关闭
    this.webSocket.on("closing", function (code, reason, ws) {
      console.log("WebSocket关闭中");
    });
    // 接收到文本消息
    this.webSocket.on("text", function (text, ws) {
      _this.onMessage && _this.onMessage(text); // 触发消息接收回调
      if(_this.isValidJSON(text)) {
        let data = JSON.parse(text);
        if(data && data.type && data.type == 'pong') {
          _this.receiveHeartbeatResponse();  // 接收到心跳回复
        }
      }
    });
    // 接收到二进制消息
    this.webSocket.on("binary", function (bytes, ws) {
      console.info("收到二进制消息");
    });
    // WebSocket 已关闭
    this.webSocket.on("closed", function (code, reason, ws) {
      console.log("WebSocket已关闭: code = %d, reason = %s", code, reason);
      _this.stopHeartbeatTimer(); // 清除心跳定时器
      _this.reconnectWebSocket(); // 断线后重新连接
    });
  };
  /**
   * 连接 WebSocket
   */
  WebSocketClient.prototype.connectWebSocket = function () {
    try {
      this.webSocket = $web.newWebSocket(this.webSocketUrl, {
        eventThread: "this", // 以当前实例作为事件处理上下文
      });
      this.initWs(); // 初始化 WebSocket 相关事件处理
    } catch (e) {
      console.log("catch" + e);
      this.reconnectWebSocket(); // 连接出错时触发重连
    }
  };
  // 判断字符串是否可以转换为JSON
  WebSocketClient.prototype.isValidJSON = function (str) {
    try {
      JSON.parse(str);
      return true;
    } catch (e) {
      return false;
    }
  };
  /**
   * 发送心跳
   */
  WebSocketClient.prototype.sendHeartbeat = function () {
    this.send({
      type: "ping", // 发送心跳包类型
      timestamp: this.getTimestamp(), // 添加时间戳
    }); // 发送心跳包
    // 启动定时器检查心跳回复
    this.startHeartbeatResponseTimer();
  };
  /**
   * 开始心跳回复计时器
   */
  WebSocketClient.prototype.startHeartbeatResponseTimer = function () {
    var _this = this;
    // 如果一分钟内没有收到心跳回复,则进行重连
    if (this.heartbeatResponseTimer) {
      clearTimeout(this.heartbeatResponseTimer);
    }
    this.heartbeatResponseTimer = setTimeout(function () {
      console.log("一分钟内没有收到心跳回复,开始重新连接...");
      _this.reconnectWebSocket();
    }, 60000); // 一分钟的毫秒数
  };
  /**
   * 停止心跳回复计时器
   */
  WebSocketClient.prototype.stopHeartbeatResponseTimer = function () {
    if (this.heartbeatResponseTimer) {
      clearTimeout(this.heartbeatResponseTimer);
    }
  };
  /**
   * 接收到心跳回复
   */
  WebSocketClient.prototype.receiveHeartbeatResponse = function () {
    this.stopHeartbeatResponseTimer(); // 收到回复,停止计时器
  };
  /**
   * 开始心跳
   */
  WebSocketClient.prototype.startHeartbeatTimer = function () {
    var _this = this;
    this.heartbeatInterval = setInterval(function () {
      return _this.sendHeartbeat(); // 每隔5秒发送心跳包
    }, 5000);
  };
  /**
   * 清除心跳
   */
  WebSocketClient.prototype.stopHeartbeatTimer = function () {
    this.heartbeatInterval && clearInterval(this.heartbeatInterval); // 清除心跳定时器
  };
  /**
   * 重连 WebSocket
   */
  WebSocketClient.prototype.reconnectWebSocket = function () {
    var _this = this;
    var _a;
    var reconnectInterval = 2000; // 重连间隔时间(毫秒)
    if (!this.disconnect) {
      if (this.isReconnecting) {
        (_a = this.webSocket) === null || _a === void 0 ? void 0 : _a.cancel(); // 取消当前重连
      }
      this.isReconnecting = true; // 设置正在重连标志
      this.reconnectTimer && clearTimeout(this.reconnectTimer); // 清除重连定时器
      if (
        this.webSocket &&
        this.webSocket != null &&
        this.webSocket != undefined
      ) {
        this.webSocket.close(1000, "尝试重新连接 WebSocket..."); // 主动关闭当前 WebSocket 连接
      }
      this.reconnectTimer = setTimeout(function () {
        console.log("尝试重新连接 WebSocket...");
        _this.connectWebSocket(); // 重新连接
      }, reconnectInterval);
    }
  };
  /**
   * 主动断开 WebSocket 连接
   */
  WebSocketClient.prototype.disconnectWebSocket = function () {
    this.disconnect = true; // 设置主动断开标志
    this.stopHeartbeatTimer(); // 停止心跳定时器
    if (
      this.webSocket &&
      this.webSocket != null &&
      this.webSocket != undefined
    ) {
      console.log("执行断开连接");
      this.webSocket.close(1000, "主动断开连接"); // 关闭 WebSocket 连接
      this.webSocket = null; // 释放 WebSocket 对象
    }
  };
  /**
   * 发送 WebSocket 消息
   */
  WebSocketClient.prototype.send = function (data) {
    data = data || {};
    data["code"] = data["code"] || 0; // 设置默认的 code
    data["timestamp"] = this.getTimestamp(); // 添加时间戳
    if (!data["type"]) throw new Error("缺失type参数"); // 如果没有指定消息类型,抛出异常
    if (!this.webSocket) return false; // 若 WebSocket 未连接,返回 false
    return this.webSocket.send(JSON.stringify(data)); // 发送消息
  };
  /**
   * 获取时间戳
   */
  WebSocketClient.prototype.getTimestamp = function () {
    return Math.floor(Date.now() / 1000); // 返回当前时间戳(秒)
  };
  return WebSocketClient;
})();

使用示例:

let ws = new WebSocketClient("wss://12...或者ws://12...");
ws.onMessage = function (message) {
  console.log("收到消息:", message);
};

以上是 WebSocketClient 类的核心部分,它包含了WebSocket客户端的实现逻辑。接下来,我们将对其实现的功能进行逐步讲解。

功能讲解

  1. 连接WebSocket

    在类的构造函数中,通过 this.connectWebSocket() 方法初始化WebSocket连接,这确保了在创建 WebSocketClient 实例时即可建立与指定URL的WebSocket连接。

  2. 发送心跳

    sendHeartbeat 方法用于向服务器发送心跳消息,其中包括了一个类型为 “ping” 的字段以及当前的时间戳。这有助于客户端和服务器之间的心跳检测,以确保连接的有效性。

  3. 心跳回复计时器

    通过 startHeartbeatResponseTimer 方法,客户端在发送心跳后启动一个计时器来检查是否在规定时间内收到了心跳回复。如果在一定时间内没有收到回复,客户端将执行重新连接操作。

通过以上功能,WebSocketClient 类实现了一套完整的WebSocket客户端逻辑,包括连接管理、心跳检测等关键功能。这使得开发者能够更加便捷地使用WebSocket进行实时通信。

结语

希望本文能够对您有所帮助,如果您有任何疑问或建议,欢迎在下方留言讨论。


希望这篇分享对你有所帮助。如果需要进一步修改或添加内容,请随时告诉我。

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享
评论 共3条

请登录后发表评论