李优秀 发表于 2024-12-4 10:37:00

vue中利用socket.io统计在线用户

目录
一、引入相关模块
二、store/modules 中封装socketio
三、后端代码(nodejs)


一、引入相关模块

main.js 中参考以下代码 ,另外socketio的利用在查阅其它相关文章时有收支,照旧只管以官方文档为准
import VueSocketIO from 'vue-socket.io'
import SocketIO from 'socket.io-client'

const SOCKETIO = new VueSocketIO({
debug: true, // true开启
connection: SocketIO('ws://127.0.0.1:8003',{
    autoConnect: false   //不自动连接
}),
options: {
    transports: ['websocket']
},
vuex: {
    store,
    actionPrefix: 'SOCKET_',
    mutationPrefix: 'SOCKET_'
}
})

Vue.use(SOCKETIO)

二、store/modules 中封装socketio

代码如下:
import io from 'socket.io-client';
import store from '../index';
import moment from 'moment';
let socket = {};
const state = {
    socket: {
      heartbeatActive: false,
      heartbeatInterval: null,
      heartbeatTimeout: null,
      reconnectAttempts: 0,
      maxReconnectAttempts: 5,
    },
}

const mutations = {
    START_HEARTBEAT(state) {
      state.heartbeatActive = true;
    },
    STOP_HEARTBEAT(state) {
      state.heartbeatActive = false;
    },
    SET_HEARTBEAT_INTERVAL(state, interval) {
      state.heartbeatInterval = interval;
    },
    SET_HEARTBEAT_TIMEOUT(state, timeout) {
      state.heartbeatTimeout = timeout;
    },
    INCREMENT_RECONNECT_ATTEMPTS(state) {
      state.reconnectAttempts += 1;
    },
    RESET_RECONNECT_ATTEMPTS(state) {
      state.reconnectAttempts = 0;
    }
}

const actions = {
    connectSocket({ commit, dispatch }) {
      socket=io('http://127.0.0.1:8003'); //socket 服务地址
      socket.connect();
      socket.on('connect', () => {
            console.log('Socket connected');
            dispatch('login');
            commit('START_HEARTBEAT');
            commit('RESET_RECONNECT_ATTEMPTS');
            dispatch('startHeartbeat');
      });
      socket.on('disconnect', () => {
            console.log('Socket disconnected');
            commit('STOP_HEARTBEAT');
            // dispatch('handleReconnect');
      });

      socket.on('pong', () => {
            console.log('Pong received');
            clearTimeout(this.state.heartbeatTimeout);
            dispatch('resetHeartbeatTimeout');
      });
    },
    login() {
      socket.emit('login',{ usercode: store.getters['name'],loginTime: moment().format('YYYY-MM-DD HH:mm:ss') });
    },
    disconnectSocket({ commit }) {
      socket.disconnect();
      clearInterval(state.heartbeatInterval);
      clearTimeout(state.heartbeatTimeout);
      commit('STOP_HEARTBEAT');
    },
    startHeartbeat({ commit, dispatch }) {
      const heartbeatInterval = setInterval(() => {
            console.log('user/usercode', store.getters['name'])
            //发送心跳包
            socket.emit('ping', { usercode: store.getters['name'],lastLoginTime: moment().format('YYYY-MM-DD HH:mm:ss') });
            dispatch('resetHeartbeatTimeout');
      }, 25000);
      commit('SET_HEARTBEAT_INTERVAL', heartbeatInterval);
    },
    resetHeartbeatTimeout({ commit, state, dispatch }) {
      if (state.heartbeatTimeout) {
            clearTimeout(state.heartbeatTimeout);
      }
      const heartbeatTimeout = setTimeout(() => {
            console.log('Heartbeat timeout, attempting to reconnect');
            dispatch('stopHeartbeat');
            dispatch('connectSocket');
      }, 30000); // 设置超时时间
      commit('SET_HEARTBEAT_TIMEOUT', heartbeatTimeout);
    },
    stopHeartbeat({ commit, state }) {
      clearInterval(state.heartbeatInterval);
      clearTimeout(state.heartbeatTimeout);
      commit('STOP_HEARTBEAT');
    },
    handleReconnect({ commit, state, dispatch }) {
      if (state.reconnectAttempts < state.maxReconnectAttempts) {
            commit('INCREMENT_RECONNECT_ATTEMPTS');
            setTimeout(() => {
                dispatch('connectSocket');
            }, 5000); // 重连间隔
      } else {
            console.log('Max reconnect attempts reached');
      }
    }
}

export default {
    namespaced: true,
    state,
    mutations,
    actions
} 触发变乱写在了AppMain.vue中
export default {
name: 'AppMain',
computed: {
    cachedViews() {
      return this.$store.state.tagsView.cachedViews
    },
    key() {
      return this.$route.fullPath
    }
},
mounted() {
    this.$store.dispatch('socketio/connectSocket'); //登陆成功后手动连接
    }
} 三、后端代码(nodejs)

单独封装了一个 socketio.js文件,这个根据个人喜好处置惩罚,简单样例代码

global.socketClients= new Map();
global.io.on('connection', (socket) => {
    console.log('a user connected');
   
    socket.on('login', (data) => {
      console.log('login',data);
      global.socketClients.set(data.usercode,data);
      console.log(global.socketClients);
    });
   
    socket.on('ping', (data) => {
      console.log('received heartbeat');
      console.log('ping',data);
      if(global.socketClients.has(data.usercode)){
            global.socketClients.set(data.usercode,_.assign(global.socketClients.get(data.usercode),data));
      }else{
            global.socketClients.set(data.usercode,data);
      }
      console.log(global.socketClients);

    });

    socket.on('disconnect', (reason) => {
      if (reason === 'ping timeout') {
            console.log('Client disconnected due to heartbeat timeout');
      } else {
            console.log('Client disconnected due to:', reason);
      }
    });
}); 相关数据可以用redis,或者放到表中进行一些其它逻辑的处置惩罚
附上后端示例:
https://i-blog.csdnimg.cn/direct/a48d0c1ee508483389718e0bddf4f80f.png
前端列表:
https://i-blog.csdnimg.cn/direct/4524eac9de2a496f8ba4138d744e0493.png

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: vue中利用socket.io统计在线用户