Ts自封装WebSocket心跳重连

WebSocket是一种在单个TCP连接上进行全双工通信的协议,允许客户端和服务器之间进行双向实时通信。

所谓心跳机制,就是在长时间不使用WebSocket连接的情况下,通过服务器与客户端之间按照一定时间间隔进行少量数据的通信来达到确认连接稳定的手段。

Js提供的原生WebSocket的API较为简陋,博主这里对其进行简单封装,使其具有心跳机制。

一、搭建测试用本地服务器

博主使用node.js建立本地WebSocket服务器,代码如下

javascript 复制代码
const WebSocket = require("ws");
const WebSocketServer = WebSocket.Server;
const wss = new WebSocketServer({ port: 3000 });
wss.on("connection", (ws) => {

  ws.on("message", (message, err) => {
    let data=JSON.parse(message.toString())
    console.log(data);
    if (err) {
      console.log(err);
    } else {
      if (data.type == "heartbeat") {
        ws.send(JSON.stringify({ "type": "heartbeat", "data": "---HeartBeatOK---" }));
      } else {
        ws.send(JSON.stringify({ "type": "normal","data": "Receive "+data.data+" OK" }));
      }
    }
  });
});

主要思路为,客户端建立连接后,进入wss.on('connection')的回调函数,开启message的监听。约定:消息为一个JSON字符串,其中包含type和data。

type是字符串类型,只有两个取值,一个是heartbeat,一个是normal。

type字段规定了消息体是心跳消息还是一般消息。

data是实际传输的数据。

这里数据传输遇到一点小问题,JSON字符串在传输过程中被转化为buffer格式,所以在接受message的时候需要调用toString方法转化为JSON字符串,然后才能用JSON.parse把内容解析出来。

如果心跳消息正常接受,服务器返回"---HeartBeatOK---";如果一般消息正常接受,服务器返回"Receive "(消息体)" OK"。

二、进行WebSocket的封装

实现心跳的思路为,每隔一段时间(记为pingTimeOut),客户端发送数据到服务器,然后开始等待,如果等待时间超出规定时间(记为pongTimeOut),就启动重连函数,否则清空当前计时器。

值得注意的是,重连函数中应该设置重连的时间间隔,不然可能会因为多次连续重连报错。

首先建立一个参数协议

javascript 复制代码
export interface OPTS {
  url: string;
  pingTimeOut?: number;
  pongTimeOut?: number;
  reconnectTimeOut?: number;
}

里面是我们可能需要修改的数值。其中url为必填,是WebSocket服务器的地址,reconnectTimeOut是连续重连的间隔时间。

javascript 复制代码
export default class Websocket {
  private opts: OPTS;
  private ws: WebSocket;
  private lockReconnect: boolean = false;
  private forbidReconnect: boolean = false;
  private heartBeatTimer;
  private serverReplyTimer;
  constructor({
    url,
    pingTimeOut = 15000,
    pongTimeOut = 10000,
    reconnectTimeOut = 2000,
  }) {
    this.opts = {
      url: url,
      pingTimeOut: pingTimeOut,
      pongTimeOut: pongTimeOut,
      reconnectTimeOut: reconnectTimeOut,
    };
    this.createWebSocket();
  }

​

构造函数中传入我们需要的数值,非必填项设置默认值,将其赋给opts,然后调用createWebSocket方法。这个方法会在下文实现。首先,设置ws变量装载WebSocket示例对象,

设置lockReconnect,这个值用来控制:当重连程序运行中,不会再次触发重连程序。

forbidReconnect则是用来控制重连程序,当我们手动调用停止WebSocket连接的时候,禁止自动重连。

javascript 复制代码
​createWebSocket() {
    try {
      this.ws = new WebSocket(this.opts.url);
      this.EventHandler();
    } catch (e) {
      console.log("create",e);
      this.reconnect();
    }
  }

​

这里创建了一个WebSocket实例对象,传入opts参数中的url。

javascript 复制代码
EventHandler() {
    this.ws.onerror = (e) => {
      console.log(e);
      this.reconnect();
    };
    this.ws.onmessage = (e) => {
      let result = JSON.parse(e.data).data;
      console.log(result);
      if (result == "---HeartBeatOK---") {
        clearTimeout(this.serverReplyTimer)
      }
    };
    this.ws.onopen = (e) => {
      this.startHeartBeat();
    };
    this.ws.onclose = (e) => {
      console.log(e);
      this.reconnect()
    };
  }

这里设置了所有当前监听ws状态变化的回调函数,其中,在onmessage回调函数中,如果收到服务器传来的心跳确认,就清除服务器回复计时器。之后的业务逻辑也可以在这里进行处理,或者另外封装业务处理函数,放在这里调用。

在onopen函数中开启心跳。

其余两种非正常状态,输出错误信息后启动重连程序。

心跳函数细节如下:

javascript 复制代码
  startHeartBeat() {
    if (this.heartBeatTimer) clearInterval(this.heartBeatTimer)
      console.log("start heart beat");
      this.ws.send(JSON.stringify({ type: "heartbeat", data: "-_-" }));
      this.heartBeatTimer = setInterval(() => {
        this.ws.send(JSON.stringify({ type: "heartbeat", data: "-_-" }));
      }, this.opts.pingTimeOut);
  }

如果创建过心跳计时器,但是由于重连的原因,重新开始心跳,就清除原来的计时器,重新创建一个心跳计时器。创建前需要立即发送一次心跳信号。计时器的时间间隔为opts中的参数。

javascript 复制代码
  reconnect() {
    clearInterval(this.heartBeatTimer)
    if (!this.lockReconnect && !this.forbidReconnect) {
      this.lockReconnect = true;
      setTimeout(() => {
        this.createWebSocket();
        this.lockReconnect = false;
      }, this.opts.reconnectTimeOut);
    }
  }

重连,清除心跳计时器,如果正在执行重连(lockReconnect控制),或者已经手动关闭连接,就直接退出。

经过规定时间(参数为连续重连的时间间隔)后重新创建WebSocket实例对象。

javascript 复制代码
 close() {
    this.ws.close();
    clearInterval(this.heartBeatTimer)
    this.forbidReconnect = true;
  }

手动关闭WebSocket连接的函数,设置禁用自动连接。同时清除心跳计时器。

博主使用Cocos进行测试,设置每次点击按钮传输0-9随机数字,同时每隔3秒进行一次心跳通信。

可以看到心跳通信正常,同时还可以进行数据传输。

相关推荐
小蜗牛慢慢爬行34 分钟前
有关异步场景的 10 大 Spring Boot 面试问题
java·开发语言·网络·spring boot·后端·spring·面试
MARIN_shen40 分钟前
Marin说PCB之POC电路layout设计仿真案例---06
网络·单片机·嵌入式硬件·硬件工程·pcb工艺
打鱼又晒网1 小时前
linux网络套接字 | 深度解析守护进程 | 实现tcp服务守护进程化
linux·网络协议·计算机网络·tcp
m0_748240021 小时前
Chromium 中chrome.webRequest扩展接口定义c++
网络·c++·chrome
終不似少年遊*1 小时前
华为云计算HCIE笔记05
网络·华为云·云计算·学习笔记·hcie·认证·hcs
蜜獾云2 小时前
docker 安装雷池WAF防火墙 守护Web服务器
linux·运维·服务器·网络·网络安全·docker·容器
小林熬夜学编程3 小时前
【Linux网络编程】第十四弹---构建功能丰富的HTTP服务器:从状态码处理到服务函数扩展
linux·运维·服务器·c语言·网络·c++·http
Hacker_Fuchen3 小时前
天融信网络架构安全实践
网络·安全·架构
上海运维Q先生3 小时前
面试题整理15----K8s常见的网络插件有哪些
运维·网络·kubernetes
ProtonBase3 小时前
如何从 0 到 1 ,打造全新一代分布式数据架构
java·网络·数据库·数据仓库·分布式·云原生·架构