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

发布于:2024-12-06 ⋅ 阅读:(23) ⋅ 点赞:(0)

目录

一、引入相关模块

二、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,或者放到表中进行一些其它逻辑的处理

附上后端示例:

前端列表:

点个赞再走~~


网站公告

今日签到

点亮在社区的每一天
去签到