使用webSockt 实时通讯

56 阅读2分钟
  • 创建一个共用的实时通讯文件 utils - sockt.ts -`export class WebSocketClient extends EventDispatcher { // #socket链接 private appid = ''; private token = ''; // #socket实例 private socket: WebSocket | null = null;

// #发送心跳数据间隔 private heartbeatInterval = 20000; // #计时器id private heartbeatTimer?: NodeJS.Timeout;

// #重连间隔 private reconnectInterval = 10000; // 10 seco // 重连状态 true 为正在重连 false 为未重连 private handleReconnectStatus = false;

// *构造函数 constructor(appid: string, token: string) { super(); // this.url = url; this.appid = appid; this.token = token; } // >生命周期钩子 onopen(callBack: Function) { this.addEventListener('open', callBack); } onmessage(callBack: Function) { this.addEventListener('message', callBack); } onclose(callBack: Function) { this.addEventListener('close', callBack); } onerror(callBack: Function) { this.addEventListener('error', callBack); }

// 消息发送 public send(message: string): void { if (this.socket && this.socket.readyState === WebSocket.OPEN) { this.socket.send(message); } else { console.error('[WebSocket] 未连接'); } } public connect(): void { console.log('connect', this.socket?.readyState); console.log('connect ttttt', this.socket); if (this.socket && this.socket.readyState === WebSocket.OPEN) { console.log('[WebSocket] 已连接'); return; }

  // let token = userStore.getToken;
  // let appid = userStore.getAppid;
  let timestamp = Math.floor(new Date().getTime() / 1000);
  let nonce = Math.floor(100000 + Math.random() * 900000).toString().padStart(8, '0');
  let version = '1.0';
  let site = 2;
  const noSha1Data = `${this.appid}${timestamp}${nonce}${version}${site}${this.token}${VITE_GLOB_WEBSOCKERT_SECRET}`;
  const sign = encrypt(sha1(noSha1Data));
  let tokenStr = encrypt(this.token);
  let appidStr = encrypt(this.appid);
  timestamp = encrypt(timestamp);
  nonce = encrypt(nonce);
  version = encrypt(version);
  site = encrypt(site);
  const url = `ws://${VITE_GLOB_WEBSOCKERT_URL}/websocket?appid=${appidStr}&timestamp=${timestamp}&nonce=${nonce}&version=${version}&site=${site}&token=${tokenStr}&sign=${sign}`;

  this.socket = new WebSocket(url);

  // websocket连接成功
  this.socket.onopen = event => {
      // 在连接成功时停止当前的心跳检测并重新启动
      this.startHeartbeat();
      this.dispatchEvent('open', event);
  };

  this.socket.onmessage = event => {
    // 接收服务端推送过来的消息
        console.log('onmessage,接受消息', event);
      this.dispatchEvent('message', event);
  };

  this.socket.onclose = event => {
    this.dispatchEvent('close', event);
  };

  this.socket.onerror = event => {
    console.log('onerror,连接错误', event);
    this.handleReconnect();
    this.dispatchEvent('error', event);
  };

}

// > 断网重连逻辑 private handleReconnect(): void { if(!this.handleReconnectStatus){ // console.log('handleReconnect', 重连); this.handleReconnectStatus = true; this.close(); setTimeout(() => { this.handleReconnectStatus = false; this.connect(); }, this.reconnectInterval);

}

}

// >开始心跳检测 -> 定时发送心跳消息 private startHeartbeat(): void { if (this.heartbeatTimer) { return; } this.heartbeatTimer = setInterval(() => { if (this.socket) { this.socket.send('h'); console.log('WebSocket', '送心跳数据...'); } else { this.handleReconnect(); } }, this.heartbeatInterval); }

// >关闭连接
public close(): void {
  this.closeHeartbeat();
    if (this.socket) {
        this.socket.close();
        this.socket = null;
        this.removeEventListener('open');
        this.removeEventListener('message');
        this.removeEventListener('close');
        this.removeEventListener('error');
    }
}

// 关闭心跳 private closeHeartbeat(): void { clearInterval(this.heartbeatTimer); this.heartbeatTimer = undefined; }

} 一般我们会 进入登录页面的时候调用调用 我们把封装的方法 写法pinia管理状态中 import { defineStore } from 'pinia'; import { WebSocketClient } from '/@/utils/socket/socket'; import { store } from '/@/store'; import { ref } from 'vue';

interface SocketHiveList { farmId: number, onlineCount: number, sleepCount: number, offlineCount: number, deviceSn: string, status: number, createTime?: any, } interface ItemHiveList { [key: string]: any }

export const useWebSocketStore = defineStore({ id: 'app-webSocket', state: () => ({ // socket实力 socket: null as WebSocketClient | null, // 蜂箱列表 离线 在线 休眠数量 hiveList:{} as SocketHiveList, // 单个蜂箱状态列表 hiveStatusList: {} as ItemHiveList, }), getters: {

//获取蜂箱 
getHiveList(): SocketHiveList {
  return this.hiveList
},

//获取单个蜂箱状态列表
getHiveStatusList(): ItemHiveList {
  return this.hiveStatusList
}

}, actions: { // 初始化链接 SocketInit(appid: string , token: string) { if (!this.socket) { console.log('初始化链接') this.socket = new WebSocketClient(appid, token); this.socket?.connect(); this.socket?.onmessage((event: any) => { // console.log(event.data,'event.data数据') const data = this.parseData(event.data) // type: 1蜂箱 if(data.type === 1){ // cmd: 0联网断网,1设备正常上传数据,2设备手动上传数据 if(data.cmd === 0){ this.hiveList = this.parseData(data.data) console.log( this.hiveList,'data.cmd === 0') } else if(data.cmd >= 1 && data.cmd <= 8){ // 1.正常上传,2.手动上传,3.设备开机,4.设备关机,5.电量低关机,6.开盖,7.关盖,8.巢脾变化 this.hiveStatusList = this.parseData(data.data) console.log( this.hiveStatusList,'data.cmd >= 1 && data.cmd <= 8')

      }
    }
    });
  }
},


Send(data: any){
  this.socket?.send(JSON.stringify(data));
},

Close(){ this.socket?.close(); }, parseData(data: string) { try { const parsedData = JSON.parse(data); if (parsedData && typeof parsedData === 'object') { return parsedData } else { console.error('Invalid data format:', data); } } catch (error) { console.error('Error parsing data:', error); } },

}, });

export function useWebSocketStoreWithOut() { return useWebSocketStore(store); }` 在路由守卫去使用 如果是组件引用的话 建议还是组件使用会比较好