webSocket 连接 心跳重连机制 思路

154 阅读1分钟

定义一个wsManager类,传入ws连接地址

class wsManager{
    constructor(url){
        this.url=url;
        this.socket=null;
    }
}

定义连接函数

    connect(){
        this.socket=new WebSocket(this.url);
        //接收消息
        this.socket.onmessage=(message)=>{
        }
        //连接成功
        this.socket.onopen=()=>{
        }
        //关闭连接
        this.socket.onclose=()=>{
        }
        //连接错误
        this.socket.onerror=()=>{
        }
    }

定时发送心跳包

    pingMessage:"ping" // 心跳发送消息
    heartbeatTime:30000 //心跳间隔
    
    // 开始发送心跳
    startHeartbeat(){
        setInterval(()=>{
            this.sendPing();
        },this.heartbeatTime)
    }
    sendPing(){
        this.socket.send(this.pingMessage);
    }

连接成功时开始发送心跳包

    this.socket.onopen=()=>{
    //添加如下代码
        this.startHearbeat();
    }

超时断开连接

    pingTimeout:null //响应超时延时器
    pingTimeoutTime:5000 //响应超时时间
    
    //心跳响应超时
    resetPingTimeout(){
        //清楚延时器
        clearTimeout(this.pingTimeout)
        //设置延时器
        this.pingTimeout=setTimeout(()=>{
            this.socket.close();
        },this.pingTimeoutTime)
    }
    
    //连接成功中添加清除延时器
    this.socket.onopen=()=>{
        //清除
        clearTimeout(this.pingTimeout)
    }
    
    //startHeartbeat中添加代码
    startHeartbeat(){
        setInterval(()=>{
            this.sendPing();
            //添加该方法调用
            this.resetPingTimeout();
        },this.heartbeatTime)
    }

断线重连

    reconnectTime:5000 //断线重连时间
    reconnectTimeout:null //重连延时器
    
    //
    reconnect(){
        this.reconnectTimeout=setTimeout(()=>{
           this.connect(); 
        },this.reconnectTime)
    }
    this.socket.onclose=()=>{
        this.reconnect();
    }

停止发送心跳

    stopHeartbeat(){
        clearInterval(this.heartbeatInterval);
        clearTimeout(this.pingTimeout);
        clearTimeout(this.reconnectTimeout);
    }

    //停止心跳
    this.socket.onclose=()=>{
        this.reconnect();
        //添加代码
        this.stopHeartbeat();
    }

整体代码

//websocket消息分发
class WebSocketManager {
 
  constructor() {
    this.url =  'ws://192.168.6.130:21110/myWs/'
    this.socket = null 
    this.user=''
    this.listeners = []
    this.heartbeatInterval = null
    this.reconnectTimeout = null
    this.pingTimeout = null
    this.pingMessage = 'ping' // 心跳消息内容
    this.heartbeatIntervalTime = 30000 // 心跳间隔
    this.pingTimeoutTime = 5000 // 5秒超时重连
  }
  connect(user) {
    if(user)this.user=user
    this.socket = new WebSocket(this.url+this.user)
    this.socket.onopen = () => {
      console.log('连接成功')
      this.startHeartbeat()
    }
    this.socket.onmessage = (message) => {
      if (message.data === this.pingMessage) {
        // 服务器响应心跳
        clearTimeout(this.pingTimeout)
      } else {
        console.log(message)
        
        this.notifyListeners(JSON.parse(message.data))
      }
    }
    this.socket.onclose = () => {
      console.log('连接断开')
      // 重连机制
      this.stopHeartbeat()
      this.reconnect()
    }
    this.socket.onerror = () => {
      console.log('连接错误')
      this.socket.close() // 触发关闭,进行重连
    }
  }
  // 重连机制
  reconnect() {
    this.reconnectTimeout = setTimeout(() => {
      console.log('尝试重连 WebSocket...')
      this.connect()
    }, 5000)
  }
  //断连
  close(){
    this.socket.onclose=()=>{
        this.stopHeartbeat()
        console.log("下机断连");
    }
    this.socket.close();
  }
  // 启动心跳检测
  startHeartbeat() {
    this.heartbeatInterval = setInterval(() => {
      this.sendPing()
    //   console.log('发送心跳包')
      this.resetPingTimeout()
    }, this.heartbeatIntervalTime)
  }
  // 停止心跳检测
  stopHeartbeat() {
    clearInterval(this.heartbeatInterval)
    clearTimeout(this.pingTimeout)
    clearTimeout(this.reconnectTimeout)
  }
  // 发送心跳包
  sendPing() {
    if (this.socket.readyState === WebSocket.OPEN) {
      this.socket.send(this.pingMessage)
    }
  }

  // 重置 ping 超时
  resetPingTimeout() {
    clearTimeout(this.pingTimeout)
    this.pingTimeout = setTimeout(() => {
      console.log('服务器未响应,重新连接...')
      this.socket.close() // 触发重连
    }, this.pingTimeoutTime)
  }
  notifyListeners(message) {
    this.listeners.forEach((listener) => listener(message))
  }

  addListener(listener) {
    this.listeners.push(listener)
  }

  removeListener(listener) {
    this.listeners = this.listeners.filter((l) => l !== listener)
  }

  setUrl(url){
    this.url=url
  }
}
//可能会有动态修改连接地址的情况。
export const wsManager = new WebSocketManager()