Websocket详解和封装

2023-03-21  本文已影响0人  扶得一人醉如苏沐晨

一、 websocket 是什么?

websocket 是一种网络通信协议,与 http 语义一样,但功能不一样
http 也是一种网络通信协议,为什么不用 http 而用 websocket ?

二、websocket 与 http 有什么区别?

websocket 通信可由服务器发起,也可以由客户端发起。可以实现客户端与服务端长连接
http 通信只能由客户端发起。


image

三、WebSocket 触发事件

以下是 WebSocket 对象的相关事件。


image

四、WebSocket 方法

假定我们使用了以上代码创建了 Socket 对象:this.Socket.close()/this.Socket.send()


image

WebSocket 组件封装(包含健康检查和心跳机制)

<template></template>

<script>
import { mapGetters } from "vuex";
export default {
  data () {
    return {
      // ws
      maxReconnect: 3, // 最大重连次数,-1代表无限重连
      reconnectTime: 0, // 重连尝试次数
      socket: "",
      uri: "",
      lockReconnect: false,
      timer: null,
      heartbeat: null,
      heartbeatTimeOut: null,
    };
  },
  computed: {
    ...mapGetters(["userInfo"]),
  },
  beforeDestroy () {
    this.destroyedWs();
  },
  methods: {
    destroyedWs () {
      console.log("ws销毁");
      // 关闭使用close方法关闭socket
      if (this.socket) {
        this.socket.close();
      }
      this.socket = null;
      // 清除定时器
      this.timer = null;
      clearInterval(this.timer);
      clearTimeout(this.heartbeat);
      this.heartbeat = null;
      clearTimeout(this.heartbeatTimeOut);
      this.heartbeatTimeOut = null;
    },
   //初始化方法
    init () {
      this.initWebSocket();
    },
    // 初始化WebSocket
    initWebSocket () {
      if (typeof WebSocket === "undefined") {
        alert("您的浏览器不支持socket");
      } else {
        const uri =
          "ws://" +
          "192.168.0.114:8686" +
          "/mqtt-print/imserver/" +
          this.userInfo.userId;
        // 实例化socket
        this.socket = new WebSocket(uri);
        // 监听socket连接
        this.socket.onopen = this.open;
        // 监听socket错误信息
        this.socket.onerror = this.error;
        // 监听socket消息
        this.socket.onmessage = this.getMessage;
        // 连接关闭
        this.socket.onclose = this.close;
      }
    },
    open: function () {
      console.log("socket连接成功");
      //开启心跳
      this.startHeartbeat();
    },
    error: function () {
      console.log("连接错误");
      //重连
      this.reconnect();
    },
    getMessage: function (msg) {
      const text = msg.data;
      //收到服务器信息,心跳重置并发送
      this.startHeartbeat();
      if (text.indexOf("ping") > 0) {
        return;
      }
      this.$emit("getMessage", text);
    },
    send: function (params) {
      this.socket.send(params);
    },
    close: function () {
      console.log("socket已经关闭");
    },
    /**
     * 重新连接(无限重连)
     */
    reconnect () {
      if (this.socket.readyState === 1) {
        // 如果状态等于1代表 websocket连接正常
        return;
      }
      if (
        this.lockReconnect ||
        (this.maxReconnect !== -1 && this.reconnectTime >= this.maxReconnect)
      ) {
        return;
      }

      // 让重连锁变为true,阻止进入下一个循环
      this.lockReconnect = true;
      setTimeout(() => {
        this.reconnectTime++;
        console.log("尝试重连");
        // 建立新连接
        this.initWebSocket();
        this.lockReconnect = false;
      }, 5000);
    },
    /**
     * 开启心跳
     */
    startHeartbeat () {
      const webSocket = this.socket;
      // 清空定时器
      clearTimeout(this.heartbeat);
      this.heartbeat = null;
      clearTimeout(this.heartbeatTimeOut);
      this.heartbeatTimeOut = null;
      // 延时发送下一次心跳
      // console.log("心跳开启");
      this.heartbeat = setTimeout(() => {
        // 如果连接正常
        // console.log("连接状态", webSocket.readyState);
        if (webSocket.readyState === 1) {
          //这里发送一个心跳,后端收到后,返回一个心跳消息,
          let params = JSON.stringify({
            type: "ping",
            toUserId: this.userInfo.userId,
          });
          webSocket.send(params);
          // 心跳发送后,如果服务器超时未响应则断开,如果响应了会被重置心跳定时器
          this.heartbeatTimeOut = setTimeout(() => {
            webSocket.close();
            // 响应超时时间
          }, 10 * 1000);
        } else {
          // 否则重连
          this.reconnect();
        }
        // 心跳间隔时间是30s
      }, 30 * 1000);
    },
  },
};
</script>
上一篇 下一篇

猜你喜欢

热点阅读