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

news2025/1/20 10:49:58

目录

一、引入相关模块

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

附上后端示例:

前端列表:

点个赞再走~~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2255771.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Redis的五种数据类型(Set、Zset)

目录 1. Set 集合1.1 Set介绍1.2 常见命令1.2.1 SADD命令1.2.2 SMEMBERS命令1.2.3 SISMEMBER命令1.2.4 SCARD命令1.2.5 SPOP命令1.2.6 SMOVE命令1.2.7 SREM命令 1.3 集合间操作1.3.1 SINTER命令1.3.2 SINTERSTORE命令1.3.3 SUNION命令1.3.4 SUNIONSTORE命令1.3.5 SDIFF命令1.3.…

【CSS in Depth 2 精译_067】11.2 颜色的定义(中):CSS 中的色域与色彩空间

当前内容所在位置&#xff08;可进入专栏查看其他译好的章节内容&#xff09; 第四部分 视觉增强技术 ✔️【第 11 章 颜色与对比】 ✔️ 11.1 通过对比进行交流 11.1.1 模式的建立11.1.2 还原设计稿 11.2 颜色的定义 11.2.1 色域与色彩空间 ✔️11.2.2 深入理解颜色表示法 文…

MVC基础——市场管理系统(一)

文章目录 项目地址一、创建项目结构1.1 创建程序以及Controller1.2 创建View1.3 创建Models层,并且在Edit页面显示1.4 创建Layou模板页面1.5 创建静态文件css中间件二、Categories的CRUD2.1 使用静态仓库存储数据2.2 将Categorie的列表显示在页面中(List)2.3 创建_ViewImport.…

[241206] X-CMD 发布 v0.4.15:env 升级,mirror 支持华为/腾讯 npm 镜像,pb-wayland 剪贴板

目录 X-CMD 发布 v0.4.15&#x1f4c3;Changelog&#x1f4e6; env|pkg&#x1fa9e; mirror&#x1f4d1; pb&#x1f3a8; theme|starship|ohmyposh&#x1f916; chat&#x1f4dd; man✅ 升级指南 X-CMD 发布 v0.4.15 &#x1f4c3;Changelog &#x1f4e6; env|pkg 新增…

# 深入浅出 快速认识JAVA常用数据结构【栈, 队列, 链表, 数组】

快速认识JAVA常用数据结构【栈, 队列, 链表】 前言 什么是数据结构 一种用来存储和组织数据的方法&#xff0c;描述了数据之间的关系和操作方式。通过合理选择和使用数据结构&#xff0c;可以大幅提高程序的运行效率、存储效率以及代码可维护性。 数据结构的重要性 数据结构…

fastadmin 后台插件制作方法

目录 一&#xff1a;开发流程 二&#xff1a;开发过程 &#xff08;一&#xff09;&#xff1a;后台功能开发 &#xff08;二&#xff09;&#xff1a;功能打包到插件目录 &#xff08;三&#xff09;&#xff1a;打包插件 &#xff08;四&#xff09;&#xff1a;安装插件…

使用Dapper创建一个简单的查询

1.先在NuGet上下载Dapper包 2.创建对应的model 代码如下&#xff1a; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks;namespace 数据显示 {public class User{public int UserId { get; set; }public…

雨晨 2610(2)0.2510 Windows 11 24H2 Iot 企业版 LTSC 2024 极简 2in1

文件: 雨晨 2610(2)0.2510 Windows 11 24H2 Iot 企业版 LTSC 2024 极简 2in1 install.esd 索引: 1 名称: Windows 11 IoT 企业版 LTSC 极简 26100.2510 描述: Windows 11 IoT 企业版 LTSC 极简 26100.2510 By YCDISM RTM 2025 24-12-07 大小: 8,176,452,990 个字节 索引: 2 …

Kubernetes 深入浅出系列 | 容器编排与作业调度之Deployment

目录 概述Deployment 的更新原理实验 概述 Kubernetes 中&#xff0c;Deployment 控制器是用于管理应用程序生命周期的核心对象。Deployment 通过管理 ReplicaSet 来间接控制 Pod&#xff0c;确保在任何时刻都能维持指定数量的 Pod 副本。这种间接管理使得 Deployment 功能比 …

网络练级宝典-> UDP传输层协议

目录 传输层 端口号 端口号和进程的关系 UDP协议 UDP协议格式 UDP数据封装&#xff1a; UDP数据分用&#xff1a; 面向数据报 UDP的缓冲区 UDP的缺点 基于UDP的应用层协议 传输层 端口号 我们知道端口号对应的其实就是一个进程的pid&#xff0c;在操作系统中二者的…

Ubuntu22.04系统源码编译OpenCV 4.10.0(包含opencv_contrib)

因项目需要使用不同版本的OpenCV&#xff0c;而本地的Ubuntu22.04系统装了ROS2自带OpenCV 4.5.4的版本&#xff0c;于是编译一个OpenCV 4.10.0&#xff08;带opencv_contrib&#xff09;版本&#xff0c;给特定的项目使用&#xff0c;这就不用换个设备后重新安装OpenCV 了&…

获取联通光猫的管理员密码

缘起&#xff1a;联通给免费更换了一个新的光猫&#xff0c;烽火的光路由&#xff0c;一个WAN口&#xff0c;4个LAN口&#xff0c;带USB接口&#xff0c;欣欣然接受。但是呢&#xff0c;发现以前的管理员密码CUAdmin不能用了。经过一系列查询&#xff0c;借助别人的经验&#x…

残差网络连接,使得输入与输出的尺寸一样

def forward(self, x):out self.layer1(x)out self.layer2(out)# 使用插值将输入x上采样至与layer2输出相同的尺寸x F.interpolate(x, size(out.size(2), out.size(3)), modebilinear, align_cornersFalse)# 确保x的通道数与out匹配x x[:, :out.size(1), :, :] # 选择前ou…

计算机网络原理之HTTP与HTTPS

一、前言 为了理解HTTP&#xff0c;我们有必要事先了解一下TCP/IP协议簇。 通常我们使用的网络&#xff08;包括互联网&#xff09;是在TCP/IP协议簇的基础上运作的。而HTTP属于它内部的一个子集。 计算机与网络设备要相互通信&#xff0c;双方必须基于相同的方法。比如&#…

实验三:Mybatis-动态 SQL

目录&#xff1a; 一 、实验目的&#xff1a; 通过 mybatis 提供的各种标签方法实现动态拼接 sql 二 、预习要求&#xff1a; 预习 if、choose、 when、where 等标签的用法 三、实验内容&#xff1a; 根据性别和名字查询用户使用 if 标签改造 UserMapper.xml使用 where 标签进行…

NLP论文速读(斯坦福大学)|使用Tree将语法隐藏到Transformer语言模型中正则化

论文速读|Sneaking Syntax into Transformer Language Models with Tree Regularization 论文信息&#xff1a; 简介&#xff1a; 本文的背景是基于人类语言理解的组合性特征&#xff0c;即语言处理本质上是层次化的&#xff1a;语法规则将词级别的意义组合成更大的成分的意义&…

C++STL容器vector容器大小相关函数

目录 前言 主要参考 vector::size vector::max_size vector::resize vector::capacity vector::empty vector::reserve vector::shrink_to_fit 共勉 前言 本文将讨论STL容器vector中与迭代器相关的函数&#xff0c;模板参数T为int类型。 主要参考 cpluscplus.com 侯…

后端-编辑按钮的实现

编辑一共要实现两步&#xff1a; 1.点击编辑蹦出来一个弹窗&#xff0c;此时需要回显&#xff0c;根据id查出来这条数据 2.修改某些值之后点击保存的时候调用修改的接口 根据id查询的时候正常操作 修改值的时候要注意一些问题 mapper层的Employee和impl层的接收实体不一样

Spring Boot漫画之家:漫画爱好者的数字图书馆

2 系统开发环境 2.1 JAVA简介 JavaScript是一种网络脚本语言&#xff0c;广泛运用于web应用开发&#xff0c;可以用来添加网页的格式动态效果&#xff0c;该语言不用进行预编译就直接运行&#xff0c;可以直接嵌入HTML语言中&#xff0c;写成js语言&#xff0c;便于结构的分离&…

RISC-V 汇编语言

安装RISCV工具链 riscv-gnu-toolchain工具链和模拟器安装记录 - 知乎 (zhihu.com) riscv-gnu-toolchain工具链分elf-gcc、linux-gnu-gcc两个版本&#xff0c;以及对应的32位和64位版本。两个版本的主要区别是&#xff1a; riscv32-unknown-elf-gcc、riscv64-unknown-elf-gcc…