【问题标题】:How do I associate multiple socketId's to one nickname in an object for socket.io and express.js?如何将多个 socketId 关联到 socket.io 和 express.js 对象中的一个昵称?
【发布时间】:2026-02-07 06:10:01
【问题描述】:

我正在开发这个节点聊天小部件:https://github.com/wwwizzarrdry/mini_chat/

  1. 您可以使用相同的昵称打开多个选项卡/窗口并且聊天工作正常(即,所有消息似乎都来自相应的用户,无论他们从哪个窗口发送)。
  2. 问题出在我的耳语功能上。向用户发送私人消息时,我只能将其发送到该用户的最后一个 socketId。因此,如果打开了 4 个窗口,则仅在最后一个窗口中接收到耳语。

问:我如何允许在同一个昵称下打开多个套接字,然后为该用户在所有窗口中保持耳语功能? 我能够为所有连接的用户建立一个 sessionId,但是不知道一旦建立了一个用户,如何重新分配一个套接字。

App.js 关键块:

    var express = require('express'),
    app = express(),
    server = require('http').createServer(app),
    io = require('socket.io').listen(server),
    mongoose = require('mongoose'),
    users = {};

    server.listen(3000);

    ........

    io.sockets.on('connection', function(socket){
    var query = Chat.find({});
    query.sort('-created').limit(25).exec(function(err, docs){
            if(err) throw err;
            socket.emit('load old msgs', docs);
    });

    socket.on('new user', function(data, callback){
            if (data in users){
                    callback(false);
            } else{
                    callback(true);
                    socket.nickname = data;
                    users[socket.nickname] = socket;
                    updateNicknames();
            }
    });

    function updateNicknames(){
            io.sockets.emit('usernames', Object.keys(users));
    }

    .......

    socket.on('send message', function(data, callback){
    var msg = data.trim();
    console.log('after trimming message is: ' + msg);
    if(msg.substr(0,3) === '/w '){
        msg = msg.substr(3);
        var ind = msg.indexOf(' ');
        if(ind !== -1){
            var name = msg.substring(0, ind);
            var msg = msg.substring(ind + 1);
            if(name in users){
                users[name].emit('whisper', {msg: msg, nick: socket.nickname});
                console.log('message sent is: ' + msg);
                console.log('Whisper!');
            } else{
                callback('Error!  Enter a valid user.');
            }
        } else{
            callback('Error!  Please enter a message for your whisper.');
        }
    } else{
        var newMsg = new Chat({msg: msg, nick: socket.nickname});
        newMsg.save(function(err){
            if(err) throw err;
             io.sockets.emit('new message', {msg: msg, nick: socket.nickname});
        });
    }

    .......

更新:使用“房间”效果很好。

    socket.on('new user', function(data, callback){
            if (data in users){
                    callback(true);
                    socket.nickname = data;
                    users[socket.nickname] = socket;
                    **socket.join(socket.nickname);**
                    updateNicknames();
            } else{
                    callback(true);
                    socket.nickname = data;
                    users[socket.nickname] = socket;
                    **rooms.push(socket.nickname);
                    socket.join(socket.nickname);**
                    updateNicknames();
            }
    });

    .......

    socket.on('send message', function(data, callback){
            var msg = data.trim();
            console.log('after trimming message is: ' + msg);
            if(msg.substr(0,3) === '/w '){
                    msg = msg.substr(3);
                    var ind = msg.indexOf(' ');
                    if(ind !== -1){
                            var name = msg.substring(0, ind);
                            var msg = msg.substring(ind + 1);
                            if(name in users){
                                      **io.sockets.in(name).emit('whisper', {msg: msg, nick: socket.nickname});**
                                      *//users[name].emit('whisper', {msg: msg, nick: socket.nickname});*
                                      console.log('message sent is: ' + msg);
                                      console.log('Whisper!');
                            } else{
                                    callback('Error!  Enter a valid user.');
                            }
                    } else{
                            callback('Error!  Please enter a message for your whisper.');
                    }
            } else{
                    var newMsg = new Chat({msg: msg, nick: socket.nickname});
                    newMsg.save(function(err){
                            if(err) throw err;
                            io.sockets.emit('new message', {msg: msg, nick: socket.nickname});
                    });
            }
    });

【问题讨论】:

    标签: node.js session express socket.io


    【解决方案1】:

    我看到了两种方法:

    • 为以相同昵称运行的每组窗口/选项卡创建一个房间。来自socket.io's docs

    房间允许对连接的客户端进行简单的分区。这允许 要向已连接客户端列表的子集发出的事件,以及 提供了一种管理它们的简单方法。

    基本上,为每个昵称创建一个房间(可能是昵称的唯一哈希),当您需要耳语时,只需将其发送到那个房间。

    • 跟踪特定于每个客户端的所有窗口/选项卡的套接字 ID,并将它们保存在数据库中。然后,一旦您需要广播耳语,只需查询所有 id,并向他们发送whisper 消息。这种方法的缺点是您需要对数据库进行一些管理(主要是删除断开连接的套接字的 ID)。

    就个人而言,我会选择第一种方法,只是因为它会带来良好的学习体验。

    【讨论】:

    • 感谢您的快速回复。该解决方案简单、快速且运行良好。
    最近更新 更多