webSocket 实时通信

383 阅读3分钟

webSocket 实时通信

http通信是单向的,没有客户端请求就不会有服务器响应,如果服务器有发生变化时,只能通过轮询实现,但是效率低且对服务器压力大,于是有了webSocket

webSocket实现了客户端和服务器的双向平等对话,具有实时性

  • 通过new创建一个实例对象,创建连接
  • onopen 连接成功后触发的函数,可在此函数内调用send()方法发送数据,进行通信
  • onmessage 收到服务器发送来的数据时触发的函数,在此函数内接受数据
  • onclose 连接关闭时触发的函数
  • onerror 连接响应意外故障时触发的函数
  • 可通过window.onbeforeunload监听窗口关闭事件执行close()方法来关闭webSocket
  • 通过readyState属性获取webSocket当前状态
0-连接尚未建立 CONNECTING
1-连接已建立 OPEN
2-连接正在关闭 CLOSING
3-连接已关闭或者连接不能打开 CLOSED

webSocket 心跳包

webSocket超时没有消息时会自动断开连接,心跳包其实就是在未超时之前,每隔一段时间send发送一次,以此来告诉服务器 客户端还需要连接,以此来保持长连接的目的.(这个超时时间是有服务器设置的)

在onopen成功建立起连接后即开启心跳包,需要判断当前是否有websocket实例对象和readyState状态为1连接状态

如果收到了服务器信息,这个时候需要重置心跳,即清除定时器重新执行心跳包,目的是重新计算定时器时间

webSocket 掉线重连

发生意外触发onerror事件,错误会导致连接关闭,很快会触发onclose,在onerror中适合做重连逻辑

data(){
    return{
       websocket: null,         // websocket实例对象
       IntervalS: null,         // 心跳倒计时对象
       socketCount:0,          // 重连次数
       lockReconnect:false,    // 避免重连 重复多次
       TimeoutS:null
    }
},
mounted () { this.initWebSocket() },

destroyed() { 
    this.clear()
    this.websocket.close() // 关闭websocket 
},

// 清除
clear(){
   clearInterval(this.IntervaObj)
   this.IntervaObj = null
   clearTimeout(this.TimeoutS)
   this.TimeoutS = null
}


// 创建 websocket 和定义事件
initWebSocket(){
    // 判断当前环境是否支持 websocket
    if (typeof (WebSocket) == 'undefined') {
       this.$notify({
          title: '提示',
          message: '当前浏览器不支持Websocket通信协议,建议使用谷歌浏览器!',
          type: 'warning',
          duration: 0
       });
    } else {
       this.websocket = new WebSocket(process.env.VUE_APP_BASE_SOCKET + "/notify")
       // 连接成功建立的回调方法
       this.websocket.onopen = this.wssOpen
       //  接受到消息的回调方法
       this.websocket.onmessage = this.wssMessage
       // 连接发生错误的回调方法
       this.websocket.onerror = this.wssError
       // 接受到服务端关闭连接时的回调方法
       this.websocket.onclose = this.wssClose
       // 监听窗口关闭事件,当窗口关闭时关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常
       window.onbeforeunload = this.closeWebSocket
    }
}

closeWebSocket(){ this.clear() }

wssOpen () {
   this.websocket.send("发送数据")
   this.start(); // 开启心跳
},

wssMessage(event){
    // 处理接受的消息
    console.log(event.data)
    // 收到服务端消息了可以重置心跳
    this.start()
},

wssError () {
   //重连3次还是连接不上则关闭websocket
   this.socketCount++;
   if(this.socketCount <= 2){
      this.reconnect(); // 重复连接
      console.log("WebSocket连接发生错误" + ' 状态码:' + this.websocket.readyState)
   }else{
       this.clear()
       this.websocket.close()
   }
},

wssClose(err){
    console.log( "连接关闭" + this.websocket.readyState,err.code)
    this.clear()
},

// 开启心跳 30s发送一次
start () {
   // 清除时间重新计算s 重置心跳
   if(this.IntervalS){
      clearInterval(this.IntervalS)
      this.IntervalS = null
   }
   this.IntervalS = setInterval(() => {
      // 如果连接正常,每30s发送心跳,否则重连
      if (this.websocket && this.websocket.readyState == 1) { // this.websocket.OPEN
         this.websocket.send(' ')
      } else {
         this.reconnect(); // 重复连接
      }
   }, 30 * 1000)
},

// 重新连接
reconnect () {
    // 避免重连 重复多次
    if(this.lockReconnect) return
    this.lockReconnect = true
   // 设置延时器避免请求过多
    this.TimeoutS = setTimeout(()=>{
      this.initWebSocket();
      this.lockReconnect = false;
   },10* 1000)
},