【问题标题】:Socket IO Rooms: Get list of clients in specific roomSocket IO Rooms:获取特定房间的客户端列表
【发布时间】:2013-08-08 06:06:02
【问题描述】:

我正在尝试显示特定房间中的客户列表。我只想显示他们的用户名,而不是他们的套接字 ID。

我现在的位置:

socket.set('nickname', "Earl");  
socket.join('chatroom1');
console.log('User joined chat room 1);

var roster = io.sockets.clients('chatroom1');
for ( i in roster )
{
   console.log('Username: ' + roster[i]);   
}

没有任何运气让它列出套接字 ID 或任何东西。但是希望它返回昵称。

【问题讨论】:

    标签: javascript node.js socket.io


    【解决方案1】:

    在 socket.IO 3.x 中

    New to version 3.x is that connected is renamed to sockets and is now an ES6 Map on namespaces. 在房间的套接字上是一个 ES6 客户端 ID 集。

    //this is an ES6 Set of all client ids in the room
    const clients = io.sockets.adapter.rooms.get('Room Name');
    
    //to get the number of clients in this room
    const numClients = clients ? clients.size : 0;
    
    //to just emit the same event to all members of a room
    io.to('Room Name').emit('new event', 'Updates');
    
    for (const clientId of clients ) {
    
         //this is the socket of each client in the room.
         const clientSocket = io.sockets.sockets.get(clientId);
    
         //you can do whatever you need with this
         clientSocket.leave('Other Room')
    
    }
    

    在 socket.IO 1.x 到 2.x 中

    请参考以下答案: Get list of all clients in specific room。复制如下,稍作修改:

    const clients = io.sockets.adapter.rooms['Room Name'].sockets;   
    
    //to get the number of clients in this room
    const numClients = clients ? Object.keys(clients).length : 0;
    
    //to just emit the same event to all members of a room
    io.to('Room Name').emit('new event', 'Updates');
    
    for (const clientId in clients ) {
    
         //this is the socket of each client in the room.
         const clientSocket = io.sockets.connected[clientId];
    
         //you can do whatever you need with this
         clientSocket.leave('Other Room')
    }
    

    【讨论】:

    • 我需要 > 1.0 的东西,但是你清楚地表明这不适用于上面的 1.0,没有理由反对。有一个 +1 来平衡它:p。
    【解决方案2】:

    不要深入socket/io对象,你可以使用简单而标准的方式:

    io.in(room_name).clients((err , clients) => {
        // clients will be array of socket ids , currently available in given room
    });
    

    更多详情DO READ

    【讨论】:

    • 如何使用 async 和 await ?
    • 请注意,此解决方案不适用于 socket.IO v3 或更高版本。
    【解决方案3】:

    只是一些事情。

    1. 当您拥有socket 后,您可以设置如下属性:socket.nickname = 'Earl'; 稍后在控制台日志中使用 save 属性: console.log(socket.nickname);

    2. 您的:

      console.log('User joined chat room 1);

    3. 我不完全确定你的循环。

    下面是修改后的代码应该可以帮助你一点,还要注意我在下面使用的循环是异步的,这可能会影响你处理数据传输的方式。

    socket.nickname = 'Earl';
    socket.join('chatroom1');
    
    console.log('User joined chat room 1');
        
    var roster = io.sockets.clients('chatroom1');
            
    roster.forEach(function(client) {
        console.log('Username: ' + client.nickname);
    });
    

    为了帮助你更多,我需要查看你所有的代码,因为这没有给我上下文。

    【讨论】:

    • “io.sockets.clients('chatroom1')”在 nodejs v1.0 及更高版本中工作吗?
    • 您好,我在io.sockets.clients('roomname')中遇到错误,mysocket版本是2.2.0
    • 虽然这是公认的答案,但它不适用于高于 socket.io 1.0 的版本。
    • 这个方法不存在了
    • 方法给出错误:客户端不是函数
    【解决方案4】:

    对于 v4,我使用了这个方法 fetchSockets()

    例子:

    let roomUsers=await io.in(`room-id`).fetchSockets()
    

    在此处查看文档: https://socket.io/docs/v3/migrating-from-3-x-to-4-0/#Additional-utility-methods

    【讨论】:

      【解决方案5】:

      如果您使用 2.0,上述所有答案以及此处 socket.io get rooms which socket is currently in 或此处 Socket.IO - how do I get a list of connected sockets/clients? 的答案要么不正确要么不完整。

      1. 在 2.0 中,io.sockets.managerio.sockets.clients 不再存在。
      2. 不使用命名空间,以下3个参数都可以获取特定房间的sockets。

        socket.adapter.rooms;

        io.sockets.adapter.rooms;

        io.sockets.adapter.sids; // the socket.id array

      3. 有了命名空间(我在这里使用了“cs”),io.sockets.adapter.rooms 会给出一个相当混乱的结果,而socket.adapter.rooms 给出的结果是正确的:

      /* socket.adapter.rooms give: */
      
      {
        "/cs#v561bgPlss6ELZIZAAAB": {
          "sockets": {
            "/cs#v561bgPlss6ELZIZAAAB": true
          },
          "length": 1
        },
        "a room xxx": {"sockets": {
          "/cs#v561bgPlss6ELZIZAAAB": true
        },
        "length": 1
        }
      }
      
      /* io.sockets.adapter.rooms give: a sid without namespace*/
      
      {
        "v561bgPlss6ELZIZAAAB": {
          "sockets": {
            "v561bgPlss6ELZIZAAAB": true
          }, "length": 1
        }
      }
      

      注意:默认房间是这样的:“Each Socket in Socket.IO is identified by a random, unguessable, unique identifier Socket#id. For your convenience, each socket automatically joins a room identified by this id。”

      目前只尝试过内存适配器,没有尝试过redis-adapter。

      【讨论】:

        【解决方案6】:

        对于socket.IO v3,这里有一个重大更改:

        Namespace.clients() 重命名为 Namespace.allSockets(),现在返回一个 Promise。

        之前:

        // all sockets in the "chat" namespace and in the "general" room
        io.of("/chat").in("general").clients((error, clients) => {
          console.log(clients); // => [Anw2LatarvGVVXEIAAAD]
        });
        

        现在 (v3):

        // all sockets in the "chat" namespace and in the "general" room
        const ids = await io.of("/chat").in("general").allSockets();
        

        Source

        如果您对 socket.IO 不太熟悉,最好知道您可以编写 io 来代替 io.of("/chat") 来使用默认命名空间。

        【讨论】:

        • 这也适用于 Socket.IO v4。准确地说,上面的示例代码返回的是一组套接字 ID,而不是实际的 Socket 对象。 io.of('/').sockets 可用于获取连接到命名空间的 Socket 实例的 Map,因此 io.of('/').sockets.get(socketId) 获取与 id 匹配的 Socket 实例。
        【解决方案7】:

        socket.io ^ 2.0

        function getRoomClients(room) {
          return new Promise((resolve, reject) => {
            io.of('/').in(room).clients((error, clients) => {
              resolve(clients);
            });
          });
        }
        
        ...
        const clients = await getRoomClients('hello-world');
        console.log(clients);
        

        输出

        [ '9L47TWua75nkL_0qAAAA',
        'tVDBzLjhPRNdgkZdAAAB',
        'fHjm2kxKWjh0wUAKAAAC' ]
        

        【讨论】:

          【解决方案8】:

          对于大于 v1.0 的 Socket.io 和节点 v6.0+ 使用以下代码:

          function getSockets(room) { // will return all sockets with room name
            return Object.entries(io.sockets.adapter.rooms[room] === undefined ?
            {} : io.sockets.adapter.rooms[room].sockets )
              .filter(([id, status]) => status) // get only status = true sockets 
              .map(([id]) => io.sockets.connected[id])
          }
          

          如果你想向他们发射一些东西,使用这个:

          getSockets('room name').forEach(socket => socket.emit('event name', data))
          

          【讨论】:

            【解决方案9】:

            Socket.io v3 开始,rooms 现在是 Adapter 的受保护属性,因此您将无法通过 io.sockets.adapter.rooms 访问它。

            改为使用:

            const clientsInRoom = await io.in(roomName).allSockets()
            

            OR 用于多个房间

            const clientsInRooms = await io.sockets.adapter.sockets(new Set([roomName, roomName2]))
            

            【讨论】:

              【解决方案10】:

              对于 Socket v.4,正确的语法是:

              const sockets = await io.in("room1").fetchSockets();
              

              https://socket.io/docs/v4/server-api/#namespacefetchsockets

              【讨论】:

                【解决方案11】:

                我刚刚将房间中的所有套接字都记录到控制台,你可以对它们做任何你喜欢的事情......

                const socketsInRoom = io.adapter.rooms[room_name];
                
                    /*Collect all participants in room*/
                    for(let participant in socketsInRoom){
                        for(let socketId in socketsInRoom[participant]){
                            console.log(socketId)
                        }
                    }
                

                【讨论】:

                  【解决方案12】:

                  您可以在 io 对象上使用适配器方法,例如

                  io.sockets.adapter.rooms.get("chatroom1")
                  

                  这将返回特定房间中已连接客户端的列表。 io.sockets.adapter.rooms 这是连接到房间的所有客户端的映射,房间名称作为键,连接的客户端是房间键的值。地图功能适用。

                  【讨论】:

                    【解决方案13】:

                    socket.io ^2.2.0

                    const socket = io(url)
                    
                    socket.on('connection', client => {
                      socket.of('/').in("some_room_name").clients((err, clients) => {
                        console.log(clients) // an array of socket ids
                      })
                    })
                    

                    【讨论】:

                    • 我怎样才能使用 async 和 await 呢?
                    • 一个简单的答案是将整个事情包装在一个异步函数中并等待回调。这可能会有所帮助:stackoverflow.com/questions/47035243/…
                    【解决方案14】:

                    此解决方案适用于

                    • socket.io:“3.0.4”
                    • socket.io-redis:“6.0.1”

                    先导入这些

                    const redis = require('socket.io-redis');
                    io.adapter(redis({ host: 'localhost', port: 6379 }));

                    socket.on('create or join', function(room) {
                        log('Received request to create or join room ' + room);
                    
                        //var clientsInRoom = io.sockets.adapter.rooms[room];
                        
                        mapObject = io.sockets.adapter.rooms // return Map Js Object
                        clientsInRoom = new Set(mapObject.get(room))
                      
                        var numClients = clientsInRoom ? clientsInRoom.size : 0;
                        log('Room ' + room + ' now has ' + numClients + ' client(s)');

                    https://socket.io/docs/v3/using-multiple-nodes/#The-Redis-adapter https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/get

                    【讨论】:

                      【解决方案15】:

                      由于我几乎没有找到关于如何在特定命名空间中获取房间的信息,所以在这里以防万一有人想知道:

                      io.of(namespaceName).adapter.rooms;

                      【讨论】:

                        【解决方案16】:

                        您可以将用户集合的数组对象创建为

                        var users = {};
                        

                        然后在服务器端,您可以在连接时将其添加为新用户

                        socket.on('new-user', function (username) {
                            users[username] = username;
                        });
                        

                        在显示用户时,您可以循环“用户”对象

                        在客户端

                        var socket = io.connect();
                        
                        socket.on('connect', function () {
                            socket.emit('new-user', 'username');
                        });
                        

                        【讨论】:

                        • 说真的,您要从客户端发送用户名而不是检查 cookie 和其他东西?是不是很容易伪造?
                        • 我建议使用带有中间件的 socket.handshake.query 进行身份验证,然后将该令牌/用户名存储为套接字属性以从服务器端引用,这样它就可以正常工作了。
                        猜你喜欢
                        • 2014-08-11
                        • 1970-01-01
                        • 2016-08-13
                        • 1970-01-01
                        • 1970-01-01
                        • 1970-01-01
                        • 1970-01-01
                        • 1970-01-01
                        • 2013-06-29
                        相关资源
                        最近更新 更多