37

I'm trying to display a list of clients in a specific room. I just want to show their username, and not their socket id.

This where I'm at:

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]);   
}

Haven't had any luck getting it to list Socket IDs or anything. Would like it to return the nicknames however.

Taurian
  • 1,660
  • 7
  • 20
  • 28

18 Answers18

77

In socket.IO 3.x

New to version 3.x is that connected is renamed to sockets and is now an ES6 Map on namespaces. On rooms sockets is an ES6 Set of client ids.

//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')

}

In socket.IO 1.x through 2.x

Please refer the following answer: Get list of all clients in specific room. Replicated below with some modifications:

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')
}
TheZ
  • 3,663
  • 19
  • 34
Sony Mathew
  • 2,929
  • 2
  • 22
  • 29
  • 1
    I need something > 1.0 but something you clearly indicate this doesn't work on 1.0 above, no reason for the downvote. Have a +1 to balance it out :p. – StackOverflowed Mar 12 '16 at 14:39
23

Instead of going deep in socket/io object , You can use simple and standard way :

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

For more detail DO READ

Vivek Doshi
  • 56,649
  • 12
  • 110
  • 122
19

Just a few things.

  1. when you have the socket you can then set the properties like: socket.nickname = 'Earl'; later to use the save property for example in a console log: console.log(socket.nickname);

  2. you where missing a closing quote (') in your:

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

  3. Im not entirely sure about your loop.

Below is the amended code should help you out a bit, also be aware the loop i am using below is asynchronous and this may effect how you handle data transfers.

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);
});

to help you out more i would need to see all your code as this does not give me context.

Community
  • 1
  • 1
Jacob Squires
  • 507
  • 4
  • 8
16

For v4 I used this method fetchSockets()

Example :

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

see documentation here : https://socket.io/docs/v3/migrating-from-3-x-to-4-0/#Additional-utility-methods

Schnitter
  • 192
  • 3
  • 6
5

All the answers above and the one here socket.io get rooms which socket is currently in or here Socket.IO - how do I get a list of connected sockets/clients? were either incorrect or incomplete if you use 2.0.

  1. In 2.0, io.sockets.manager and io.sockets.clients don't exist anymore.
  2. Without using namespace, the following 3 parameters can all get sockets in a specific room.

    socket.adapter.rooms;

    io.sockets.adapter.rooms;

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

  3. With namespace (I used "cs" here), io.sockets.adapter.rooms will give a quite confusing result and the result socket.adapter.rooms gives is correct:

/* 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
  }
}

Note: the default room is this: "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."

I only tried memory adapter so far, have not tried redis-adapter.

William Jones
  • 809
  • 2
  • 11
  • 29
Qiulang
  • 10,295
  • 11
  • 80
  • 129
3

For socket.IO v3 there's a breaking change here:

Namespace.clients() is renamed to Namespace.allSockets() and now returns a Promise.

BEFORE:

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

Now (v3):

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

Source

In case you're not so familiar with socket.IO, it might be good to know that instead of io.of("/chat") you can write io to use the default namespace.

pa1nd
  • 392
  • 3
  • 16
  • This also works in Socket.IO v4. To be precise, the example code above returns a Set of socket IDs, not the actual Socket objects. `io.of('/').sockets` can be used to get a Map of Socket instances connected to a namespace so `io.of('/').sockets.get(socketId)` gets the Socket instance matching the id. – Samuli Asmala Mar 26 '21 at 07:45
3

For Socket v.4 correct syntax would be:

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

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

nojitsi
  • 351
  • 3
  • 13
3

In socket.IO 4.x

const getConnectedUserIdList = async () => {
  let connectedUsers = [];
  let roomUsers = await io.in(`members`).fetchSockets();
  roomUsers.forEach((obj) => {
    connectedUsers.push(obj.request.user.id);
  });
  return connectedUsers;
};
Nijat Aliyev
  • 558
  • 6
  • 15
2

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);

Output

[ '9L47TWua75nkL_0qAAAA',
'tVDBzLjhPRNdgkZdAAAB',
'fHjm2kxKWjh0wUAKAAAC' ]
gmspacex
  • 642
  • 5
  • 12
2

From Socket.io v3, rooms is now a protected property of Adapter so you won't be able to access it via io.sockets.adapter.rooms.

Instead use:

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

OR for multiple rooms

const clientsInRooms = await io.sockets.adapter.sockets(new Set([roomName, roomName2]))
ian chen
  • 21
  • 1
1

For Socket.io greater than v1.0 and node v6.0+ use the following code:

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])
}

If you want to emit something to them , use this :

getSockets('room name').forEach(socket => socket.emit('event name', data))
Ezzat
  • 931
  • 6
  • 13
1

This solution is for

  • socket.io : "3.0.4"
  • socket.io-redis : "6.0.1"

import these first

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

Shahzaib
  • 11
  • 2
0

I just logged all sockets in a room to the console, you can do whatever you like with them...

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)
        }
    }
Peter Moses
  • 1,997
  • 1
  • 19
  • 22
0

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
  })
})
Tomer Shetah
  • 8,413
  • 7
  • 27
  • 35
Isaac Pak
  • 4,467
  • 3
  • 42
  • 48
0

you can use the adapter method on io object like

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

this will return the list of connected clients in the particular room. io.sockets.adapter.rooms this is a map off all clients connected to rooms with room name as keys and the connected clients are the values of the room key. map functions are applicable .

vinay sandesh
  • 918
  • 9
  • 8
0

Since I have found very little on how to get the rooms inside a specific namespace, here it is in case anyone is wondering :

io.of(namespaceName).adapter.rooms;

PedroMiotti
  • 995
  • 10
  • 13
0
let sockets = await io
              .of("/namespace")
              .in(ROOM_NAME)
              .allSockets();

you can get length of connected clients via

console.log(receiver.size);
Parth Mahida
  • 604
  • 1
  • 5
  • 19
-3

You can create an array object of user collection as

var users = {};

then on server side you can add it as new user when you connect

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

while displaying the users, you can loop the "users" object

On Client side

var socket = io.connect();

socket.on('connect', function () {
    socket.emit('new-user', 'username');
});
Jeet
  • 717
  • 6
  • 18
  • seriously, you're gonna send the username from the client side instead of checking the cookies and stuff? isn't it extremely easily fakable? – Steel Brain Sep 08 '14 at 07:41
  • I would recommend using the socket.handshake.query with middleware to authenticate, then store that token/username as a socket property to refer to from the server-side so it will just work. – King Friday Aug 16 '17 at 18:12