使用 socket.io 防止向多个房间发送消息

Posted

技术标签:

【中文标题】使用 socket.io 防止向多个房间发送消息【英文标题】:Prevent emiting message to multiple rooms using socket.io 【发布时间】:2018-06-15 21:38:15 【问题描述】:

我使用这个单聊天室示例作为参考设置了一个多房间 socket.io / nodeJS 聊天服务器:

https://raw.githubusercontent.com/socketio/socket.io/master/examples/chat/index.js

我使用这个文档将代码从单房间修改为多房间:

https://socket.io/docs/rooms-and-namespaces/

我还修改了代码以在端口 8080 上使用 HTTPS 而不是 HTTP。

我已经实现了多个房间。但是,随着新用户加入不同的聊天室,他们的消息会发送到所有其他聊天室。我想这可能是因为每个人都加入了原来的房间。我的节点控制台日志中的示例:

加入:测试 //user1 加入:测试 //user2 加入:test2 //user3 user1 在测试中说了些什么 user2 正在输入 test user3 在测试中说了些什么

房间应该通过 URL GET 参数动态加入,例如 ?room=room123

这里是 nodeJS index.js 代码。客户端代码与上面的 github 链接中的代码几乎相同。我对节点和 JS 相当陌生。有什么想法吗?

// Setup basic express server
var express = require('express');
var app     = express();
var path    = require('path');
var fs      = require('fs');
var https   = require('https');
var url     = require('url');

var privateKey  = fs.readFileSync('/etc/letsencrypt/live/hostname/privkey.pem', 'utf8');
var certificate = fs.readFileSync('/etc/letsencrypt/live/hostname/fullchain.pem', 'utf8');
var credentials = key: privateKey, cert: certificate;
var server = https.createServer(credentials, app);


var io = require('socket.io')(server);
var port = process.env.PORT || 8080;

/* CONSOLE COLORS */
var GREEN  = '\033[0;32m';
var LBLUE  = '\033[1;34m';
var BLUE   = '\033[0;34m';
var RED    = '\033[0;31m';
var YELLOW = '\033[0;33m';
var PURPLE = '\033[0;35m';
var NC     = '\033[0m'; // No Color Reset

/* Chatroom Settings */
var numUsers = 0;
var roomID = null;


server.listen(port, function () 
  console.log('HTTPS Server listening on port ' + GREEN + '%d' + NC, port);
);

/* Routing */
app.use(express.static(path.join(__dirname, 'public')));


chat();



function chat()

  // multiple rooms
  io.on('connection', function(socket)
    var addedUser = false;
    var referer = url.parse(socket.handshake.headers.referer);
    var query = (referer.query).split("=");
    roomID = query[1];
    socket.join(roomID);


/* // attempt to resolve issue of sending messages to all rooms
console.log(socket.adapter.sids);
    if(Object.keys(socket.adapter.sids).length < 1)
      console.log('Connecting to room:' + roomID);
      socket.join(roomID);
    
*/

    console.log("Joining: " + YELLOW + roomID + NC);
    //console.log("UUID: " + Object.keys(socket.adapter.nsp.connected)[0]);
    //console.log("unique room id:" + Object.keys(socket.adapter.sids));


    // when the client emits 'new message', this listens and executes
    socket.on('new message', function (data) 
      // we tell the client to execute 'new message'
      socket.to(roomID).emit('new message', 
        username: socket.username,
        message: data
      );

      console.log(socket.username + ' said something in \t' + YELLOW + roomID + NC);
    );

    // when the client emits 'add user', this listens and executes
    socket.on('add user', function (username) 
      if (addedUser) return;
      // we store the username in the socket session for this client
      socket.username = username;
      ++numUsers;
      addedUser = true;
      socket.emit('login', 
        numUsers: numUsers,
    );

      // echo to room that a person has connected
      socket.to(roomID).emit('user joined', 
        username: socket.username,
        numUsers: numUsers
      );

    );

    // when the client emits 'typing', we broadcast it to others
    socket.on('typing', function () 
      console.log(socket.username + ' is typing in \t' + YELLOW + roomID + NC);
      socket.to(roomID).emit('typing', 
        username: socket.username
      );
    );

    // when the client emits 'stop typing', we broadcast it to others
    socket.on('stop typing', function () 
      socket.to(roomID).emit('stop typing', 
        username: socket.username
      );
    );

      // when the user disconnects.. perform this
      socket.on('disconnect', function () 
        console.log(socket.username + PURPLE + ' disconnected' + NC
                                    + ' from ' + YELLOW + roomID + NC);
        if (addedUser) 
          --numUsers;
          // echo that this client has left
          socket.to(roomID).emit('user left', 
            username: socket.username,
            numUsers: numUsers
          );
        
      );

    );


【问题讨论】:

【参考方案1】:

问题最终是由全局“var roomID”变量引起的。一旦我在所有 socket.to(query[1]).emit 函数中使用了 query[1] 变量,它就起作用了。

【讨论】:

【参考方案2】:

我在您的代码中看到所有套接字都使用相同的 roomID 变量。他们每个人都需要有自己的roomID 变量。

【讨论】:

roomID 变量是通过 URL 设置的。我不确定你的意思。 您通过roomID 存储房间值,它在chat 函数之外声明 我认为它是一个全局变量。控制台日志每次都显示正确的 roomID。 一个全局变量应该在所有连接之间共享,但是你的连接可能有不同的roomID 对吧? 如果我控制台记录了它正确显示的 roomID,就像在 URL 中一样。你有什么建议我做的不同吗?

以上是关于使用 socket.io 防止向多个房间发送消息的主要内容,如果未能解决你的问题,请参考以下文章

使用Socket.io将消息发送到多个房间?

如何使用nodejs socket.io向特定房间中的用户发送打字警报和消息

Socket.io 不会在断开连接时向房间发送消息

无法向socket.io中的房间发送消息

套接字 io 不向房间发送消息

Socket.io 向房间里的每个人发出,除了发件人[重复]