• WebSocket心跳机制



    1 WebSocket简介

    WebSocket是HTML5开始提供的一种浏览器与服务器进行全双工通讯的网络技术,属于应用层协议。
    WebSocket 使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。

    前后端通信请看以下内容:
    使用WebSocket实现服务端和客户端的通信:https://blog.csdn.net/ZGL_cyy/article/details/117845647
    WebSocket网页聊天室:https://blog.csdn.net/ZGL_cyy/article/details/118438572
    WebSocket区分不同客户端方法:https://blog.csdn.net/ZGL_cyy/article/details/122838063

    2 WebSocket事件与方法

    2.1 创建WebSocket实例

        var socketObj;
        if ("WebSocket" in window) {
          socketObj = new WebSocket(webSocketLink);
        } else if ("MozWebSocket" in window) {
          socketObj = new MozWebSocket(webSocketLink);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    2.2 WebSocket 事件

    img

    2.3 WebSocket 方法

    img

    方法.png

    3 WebSocket的心跳重连机制

    3.1 问题

    (1)websocket在连接后,如果长时间服务端和客户端不发消息,服务端会把websocket给断开。
    (2)存在网络忽然断开的情况,这时服务器端并没有触发onclose的事件。服务器会继续向客户端发送多余的信息,这些数据会丢失。

    3.2 心跳重连机制

    为了解决上面的问题,就需要⼀种机制来检测客户端和服务端是否处于正常的连接状态。因此就有了websocket的心跳机制

    ⼼跳机制是客户端每隔⼀段时间会向服务端发送⼀个数据包,告诉服务端自己还活着,同时客户端会根据服务端是否会回传⼀个数据包来确定服务端是否还活着。
    如果客户端没有收到回复,表示websocket断开连接或者网络出现问题,就需要重连。

    4 实际使用

    详细代码如下:

    <template>
      <div>div>
    template>
    <script>
    export default {
      data() {
        return {
          // websocket相关
          socketObj: "", // websocket实例对象
          //心跳检测
          heartCheck: {
            vueThis: this, // vue实例
            timeout: 10000, // 超时时间
            timeoutObj: null, // 计时器对象——向后端发送心跳检测
            serverTimeoutObj: null, // 计时器对象——等待后端心跳检测的回复
            // 心跳检测重置
            reset: function () {
              clearTimeout(this.timeoutObj);
              clearTimeout(this.serverTimeoutObj);
              return this;
            },
            // 心跳检测启动
            start: function () {
              this.timeoutObj && clearTimeout(this.timeoutObj);
              this.serverTimeoutObj && clearTimeout(this.serverTimeoutObj);
              this.timeoutObj = setTimeout(() => {
                // 这里向后端发送一个心跳检测,后端收到后,会返回一个心跳回复
                this.vueThis.socketObj.send("HeartBeat");
                console.log("发送心跳检测");
                this.serverTimeoutObj = setTimeout(() => {
                  // 如果超过一定时间还没重置计时器,说明websocket与后端断开了
                  console.log("未收到心跳检测回复");
                  // 关闭WebSocket
                  this.vueThis.socketObj.close();
                }, this.timeout);
              }, this.timeout);
            },
          },
          socketReconnectTimer: null, // 计时器对象——重连
          socketReconnectLock: false, // WebSocket重连的锁
          socketLeaveFlag: false, // 离开标记(解决 退出登录再登录 时出现的 多次相同推送 问题,出现的本质是多次建立了WebSocket连接)
        };
      },
      created() {
        console.log("离开标记", this.socketLeaveFlag);
      },
      mounted() {
        // websocket启动
        this.createWebSocket();
      },
      destroyed() {
        // 离开标记
        this.socketLeaveFlag = true;
        // 关闭WebSocket
        this.socketObj.close();
      },
      methods: {
        // websocket启动
        createWebSocket() {
          let webSocketLink = "wss://uat.sssyin.cn/ws-reservation"; // webSocket地址
          // console.log(webSocketLink);
          try {
            if ("WebSocket" in window) {
              this.socketObj = new WebSocket(webSocketLink);
            } else if ("MozWebSocket" in window) {
              this.socketObj = new MozWebSocket(webSocketLink);
            }
            // websocket事件绑定
            this.socketEventBind();
          } catch (e) {
            console.log("catch" + e);
            // websocket重连
            this.socketReconnect();
          }
        },
        // websocket事件绑定
        socketEventBind() {
          // 连接成功建立的回调
          this.socketObj.onopen = this.onopenCallback;
          // 连接发生错误的回调
          this.socketObj.onerror = this.onerrorCallback;
          // 连接关闭的回调
          this.socketObj.onclose = this.oncloseCallback;
          // 向后端发送数据的回调
          this.socketObj.onsend = this.onsendCallback;
          // 接收到消息的回调
          this.socketObj.onmessage = this.getMessageCallback;
    
          //监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。
          window.onbeforeunload = () => {
            this.socketObj.close();
          };
        },
        // websocket重连
        socketReconnect() {
          if (this.socketReconnectLock) {
            return;
          }
          this.socketReconnectLock = true;
          this.socketReconnectTimer && clearTimeout(this.socketReconnectTimer);
          this.socketReconnectTimer = setTimeout(() => {
            console.log("WebSocket:重连中...");
            this.socketReconnectLock = false;
            // websocket启动
            this.createWebSocket();
          }, 4000);
        },
        // 连接成功建立的回调
        onopenCallback: function (event) {
          console.log("WebSocket:已连接");
          // 心跳检测重置
          this.heartCheck.reset().start();
        },
        // 连接发生错误的回调
        onerrorCallback: function (event) {
          console.log("WebSocket:发生错误");
          // websocket重连
          this.socketReconnect();
        },
        // 连接关闭的回调
        oncloseCallback: function (event) {
          console.log("WebSocket:已关闭");
          // 心跳检测重置
          this.heartCheck.reset();
          if (!this.socketLeaveFlag) {
            // 没有离开——重连
            // websocket重连
            this.socketReconnect();
          }
        },
        // 向后端发送数据的回调
        onsendCallback: function () {
          console.log("WebSocket:发送信息给后端");
        },
        // 接收到消息的回调
        getMessageCallback: function (msg) {
          // console.log(msg);
          console.log(msg.data);
          if (msg.data.indexOf("HeartBeat") > -1) {
            // 心跳回复——心跳检测重置
            // 收到心跳检测回复就说明连接正常
            console.log("收到心跳检测回复");
            // 心跳检测重置
            this.heartCheck.reset().start();
          } else {
            // 普通推送——正常处理
            console.log("收到推送消息");
            let data = JSON.parse(msg.data);
            // 相关处理
            console.log(data);
          }
        },
      },
    };
    script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
  • 相关阅读:
    为什么花了上百万,供应链还是一团糟?看这一篇就够了!
    【附源码】Python计算机毕业设计特大城市地铁站卫生防疫系统
    容联云入选IDC生成式AI图谱,多个案例被评典型应用
    餐饮软件开发价格受到需求的影响!
    刷爆力扣之最长连续递增序列
    SpringBoot整合quartz实现定时任务
    做个小工具按规则筛选当前Object并输出基础信息
    JVM执行流程
    AutoSAR入门到精通讲解 (AuroSAR-CP描述) 1.1 AutoSAR-CP简介
    Spring的创建和使用
  • 原文地址:https://blog.csdn.net/ZGL_cyy/article/details/126494116