Nodejs node+socket.io+mysql 多房间聊天室的退出问题。

Nodejs node+socket.io+mysql 多房间聊天室的退出问题。

目前正在用node+socket.io+mysql 做一个类似QQ群的多房间聊天室。遇到一些问题,盼望大侠能指点一二。 每一个用户可能有多个群,聊天室。上线通知这个好搞定。难点是由于聊天室都是基于浏览器的,可能有多标签、多窗口状态。如何判断用户退出、关闭、刷新浏览器的行为。还有就是如何区分是退出一个房间,还是退出了所有房间(多标签浏览器,如火狐,谷歌等)

2 回复

Node.js + Socket.io + MySQL 多房间聊天室的退出问题

目前我正在使用 Node.js、Socket.io 和 MySQL 构建一个类似于 QQ 群的多房间聊天室。在这个过程中遇到了一些问题,希望得到大家的帮助。

需求描述

  • 用户可以加入多个聊天室(类似于 QQ 群)。
  • 当用户退出、关闭或刷新浏览器时,需要正确处理用户的退出行为。
  • 需要区分用户是否退出了某个特定的聊天室,或者退出了所有聊天室。

解决方案

1. 用户登录与房间加入

首先,我们需要记录用户的登录信息,并且当用户加入聊天室时,将该用户与聊天室关联起来。

// server.js
const io = require('socket.io')(server);

io.on('connection', (socket) => {
    socket.on('login', (username, callback) => {
        // 登录逻辑,存储用户信息
        socket.username = username;
        callback({ success: true });
    });

    socket.on('joinRoom', (roomId, callback) => {
        socket.join(roomId);
        // 将用户加入到数据库中的房间
        db.query(`INSERT INTO user_rooms (user_id, room_id) VALUES (?, ?)`, [userId, roomId], (err, res) => {
            if (err) return callback({ success: false, message: 'Failed to join room' });
            callback({ success: true });
        });
    });
});
2. 监听用户行为

我们需要监听用户的各种行为,包括退出、关闭或刷新浏览器。

io.on('connection', (socket) => {
    socket.on('disconnect', () => {
        // 用户断开连接时,从所有房间中移除
        Object.keys(socket.rooms).forEach((roomId) => {
            socket.leave(roomId);
            // 更新数据库中的用户状态
            db.query(`UPDATE user_rooms SET status = 'offline' WHERE user_id = ? AND room_id = ?`, [userId, roomId], (err, res) => {
                if (err) console.error(err);
            });
        });
    });

    socket.on('leaveRoom', (roomId, callback) => {
        socket.leave(roomId);
        // 更新数据库中的用户状态
        db.query(`UPDATE user_rooms SET status = 'offline' WHERE user_id = ? AND room_id = ?`, [userId, roomId], (err, res) => {
            if (err) return callback({ success: false, message: 'Failed to leave room' });
            callback({ success: true });
        });
    });
});
3. 区分退出行为

为了区分用户是否退出了一个特定的聊天室,或者退出了所有聊天室,我们可以在客户端发送不同的事件给服务器。

// client.js
socket.on('disconnect', () => {
    // 用户主动离开所有房间
    socket.emit('leaveAllRooms');
});

socket.on('leaveRoom', (roomId) => {
    // 用户离开某个特定的房间
    socket.emit('leaveRoom', roomId);
});

通过以上方法,我们可以有效地处理用户退出、关闭或刷新浏览器的行为,并且能够区分用户是否退出了某个特定的聊天室,或者退出了所有聊天室。


要解决这个问题,我们需要处理用户退出聊天室时的不同情况,包括关闭浏览器、刷新页面或切换到其他标签页。我们可以通过监听这些事件并相应地更新用户的在线状态来实现这一点。

解决方案

  1. 监听浏览器关闭事件

    • 使用 beforeunloadunload 事件来检测用户是否即将离开页面。
  2. 处理页面刷新

    • 页面刷新也会触发 beforeunloadunload 事件,因此可以在这些事件中处理用户的退出逻辑。
  3. 多房间管理

    • 需要在服务器端维护每个用户的房间列表,并在用户离开时更新这些信息。
  4. 数据库同步

    • 使用 Socket.IO 将用户的在线状态变化同步到 MySQL 数据库中。

示例代码

客户端代码 (Browser)

let socket = io();

// 监听窗口关闭事件
window.addEventListener('beforeunload', function (e) {
    // 发送退出消息给服务器
    socket.emit('leaveRoom', { roomId: currentRoomId });
});

// 当前用户加入的房间列表
let rooms = [];

// 监听从服务器接收到的消息
socket.on('joinedRoom', function(data) {
    rooms.push(data.roomId);
});

socket.on('leftRoom', function(data) {
    rooms = rooms.filter(room => room !== data.roomId);
});

服务器端代码 (Node.js)

const express = require('express');
const http = require('http');
const socketIo = require('socket.io');
const mysql = require('mysql');

const app = express();
const server = http.createServer(app);
const io = socketIo(server);

io.on('connection', function(socket) {
    socket.on('joinRoom', function(data) {
        socket.join(data.roomId);
        io.to(data.roomId).emit('joinedRoom', { roomId: data.roomId, userId: data.userId });

        // 更新数据库中的用户房间信息
        updateDatabase(data.userId, 'add', data.roomId);
    });

    socket.on('leaveRoom', function(data) {
        socket.leave(data.roomId);
        io.to(data.roomId).emit('leftRoom', { roomId: data.roomId, userId: data.userId });

        // 更新数据库中的用户房间信息
        updateDatabase(data.userId, 'remove', data.roomId);
    });

    function updateDatabase(userId, action, roomId) {
        const connection = mysql.createConnection({
            host: 'localhost',
            user: 'root',
            password: 'password',
            database: 'chat_app'
        });

        let sql;
        if (action === 'add') {
            sql = `INSERT INTO user_rooms (userId, roomId) VALUES (${userId}, ${roomId})`;
        } else {
            sql = `DELETE FROM user_rooms WHERE userId = ${userId} AND roomId = ${roomId}`;
        }

        connection.query(sql, function(error, results, fields) {
            if (error) throw error;
            connection.end();
        });
    }
});

server.listen(3000, () => {
    console.log('Server is running on port 3000');
});

以上代码展示了如何在客户端和服务器端处理用户加入和离开房间的逻辑,并将这些变化同步到 MySQL 数据库中。这样可以确保用户的在线状态在不同标签页和窗口之间保持一致。

回到顶部