【自用笔记】webSocket 心跳机制、断线重连

本文介绍了如何在业务场景中使用WebSocket实现实时位置上传,并设置了心跳机制以防止断线,包括开启/关闭socket、连接WebSockets、心跳定时发送经纬度以及断线后的重连策略。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在业务中需要使用webSocket定时给后台上传位置,防止以后忘记,在这里进行记录,直接在代码中写入笔记;

<template>
  <div id='main' ref='main'>
    <van-button @click="OnLocation">开启</van-button>
    <van-button @click="OnClose">关闭socket</van-button>    
  </div>
</template>
<script>
    export default {
        data() {
            return {
                lc: {},                 // 经纬度
                ws: null,               // webSocket实例
                webSocketState: false,  // webSocket的连接状态
                heartBeat: {            // 心跳连接的时间设置
                  time: 5 * 1000,      // 心跳时间间隔
                  timeout: 3 * 1000,   // timeout:心跳超时间隔(!要少于心跳间隔)
                  reconnect: 10 * 1000  // 断线重连时间
                },
                reconnectTimer: null,  // 断线重连时间器
            }
        },
        methods: {
            OnClose() {
                this.ws.close();              //关闭webSocket连接
                this.webSocketState = false;  //关闭状态
                this.heartBeat.time = null;   //停止心跳
                if (this.reconnectTimer) {    //关闭重连
                  clearInterval(this.reconnectTimer);
                }
             },
            //开启按钮
            OnLocation() {
                this.heartBeat.time =  5 * 1000;  //因为关闭时会置空,所以在这重新初始化一下
                this.wlhy.getLocation();          //这里是我自己业务中取经纬度的,
                this.connectWebSocket();          //建立连接
            },
            //socket链接
            connectWebSocket() {
                let url = `wss://ws://baidu.com/msg/${this.userInfo.userId}`;  
                //这里连接地址根据自己的业务设置,注意:如果连接本地进行调试的时候,要用'ws',如:“ws://192.168.2.15:8080/msg”
                this.ws = new WebSocket(url);
                this.init();  //初始化
             },
             init() {
                this.ws.addEventListener('open', () => {
                // eslint-disable-next-line spaced-comment
                this.webSocketState = true; //socket状态设置为连接,做为后面的断线重连的拦截器
                // eslint-disable-next-line no-unused-expressions
                console.log('开启');
                this.heartBeat && this.heartBeat.time ?     this.startHeartBeat(this.heartBeat.time) : ''; // 是否启动心跳机制
                });
                this.ws.addEventListener('message', (e) => {
                  this.webSocketState = true;
                  console.log(JSON.parse(e.data),'信息')
                });
                this.ws.addEventListener('close', (e) => {
                  this.webSocketState = false; // socket状态设置为断线
                  console.log('断开了连接');
                });
                this.ws.addEventListener('error', (e) => {
                  this.webSocketState = false; // socket状态设置为断线
                  this.reconnectWebSocket(); // 重连
                  console.log('连接发生了错误');
                });
              },
              // 心跳  time:心跳时间间隔
              startHeartBeat(time) {
                setTimeout(() => {
                  //这里设置这是你要发送的内容
                  let data = {};
                  data.lon = this.lc.longitude;            //已省略获取地址步骤
                  data.lat = this.lc.latitude;
                  this.ws.send(JSON.stringify(data))       //发送数据
                  this.waitingServer();                    
                }, time);
              },
             // 延时等待服务端响应,通过webSocketState判断是否连线成功
              waitingServer() {
                this.webSocketState = false;  
                setTimeout(() => {
                  if (this.webSocketState) {
                    this.startHeartBeat(this.heartBeat.time);
                    return;
                  }
                  console.log('心跳无响应,已断线');
                  try {
                    this.ws.close();
                  } catch (e) {
                    console.log('连接已关闭,无需关闭');
                  }
                  this.reconnectWebSocket();  //非主动关闭导致,触发重连
                }, this.heartBeat.timeout);
              },
              // 重连操作
              reconnectWebSocket() {
                this.reconnectTimer = setTimeout(() => {
                  this.reconnectWs();
                }, this.heartBeat.reconnect);
              },
              reconnectWs() {
                if(!this.heartBeat.time) return //如果主动关闭,则防止重连
                if (!this.ws) {
                  // 第一次执行,初始化
                  this.connectWebSocket();
                }
                if (this.ws && this.reconnectTimer) {
                  // 防止多个websocket同时执行
                  clearTimeout(this.reconnectTimer);
                  this.ws.reconnectTimer = null;
                  this.connectWebSocket();
                }
              },
        },

    }
</script>

注意:我在开发过程中发现,当我主动关闭连接后,在重连时间内会自动重新开启连接,这是因为websocket连接关闭会又走一次重连机制,所以 如果你是使用的定时器,可以直接清除定时器,或者定义一个变量控制是组件销毁关闭的websocket还是心跳监测重连时关闭的websocket,如果是像我一样,可以判断this.heartBeat.time,关闭后置空,判断return就可以了;

下面是直接用定时器做的心跳(在这里没有主动关闭的功能)

<script>
    export default {
    name: "clockIn",
    data(){
      return {
        lc: {},           //经纬度(获取过程省略)
        interval: null,   //定时器
        socket: null,     //socket
      }
    },
    mounted() {},
    methods: {
        initSocket() {
            /**主流浏览器都支持 webSocket 通信,但建议还是要判断*/
            if ("WebSocket" in window) {
              if (this.socket) {
                this.socket.close();
              }
              /**创建 web socket 实例
               * 如果连接失败,浏览器控制台报错,连接失败
               * 前缀 ws:// 必须正确,weChatInteract 是应用名称,webSocket/shake.action 是后台访问路径
               * */
              
              let url = `ws://192.168.2.15:8080/msg`;
              this.socket = new WebSocket(url);

              let _this = this;
              /**onopen:服务器连接成功后,自动触发*/
              this.socket.onopen = function() {
                this.interval = setInterval(function() {
                  /** Web Socket 已连接上,使用 send() 方法发送数据*/
                  let data = {};
                  data.lon = lc.longitude;
                  data.lat = lc.latitude;
                  console.log(data)
                  _this.socket.send(JSON.stringify(data))
                  console.log("服务器连接成功,并发送数据到后台...");
               },30000)
             }

             /**服务器发送数据后,自动触发此方法,客户端进行获取数据,使用 evt.data 获取数据*/
             this.socket.onmessage = function(msg) {
                if (msg.data && msg.data != 'messageCenter login success') {
                  // let message = JSON.parse(msg.data);
                  console.log(message,'=> 接收到服务器数据')
                }
              }

            /**客户端与服务器数据传输错误时触发*/
            this.socket.onerror = function (evt) {
                console.log("客户端 与 服务器 数据传输错误...");
            };

            /**web Socket 连接关闭时触发*/
            this.socket.onclose = function(e) {
                console.log("web scoket 连接关闭...");
                if (this.interval) {
                  clearInterval(this.interval);
                }
                setTimeout(function() {
                  _this.initSocket();
                },5000)
            }

         } else {
              console.log("浏览器不支持 WebSocket!");
         }
      },
    },
</script>

参考链接:

websocket的基础使用,心跳机制,断线重连_websocket断开后怎么自动连接-优快云博客

关于WebSocket的心跳重连机制(详解)_websocket 心跳-优快云博客

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值