Socket.io: How to count clients in a room with Socket.io-redis adapter
Asked Answered
V

4

18

I start building chat server using Socket.io with multiple nodes. It uses Socket.io-redis to connect all servers together and rooms for messaging.

When a client connects with server I join client to some room.

io.on('connection', function(socket){
  socket.join("CLIENT_1");
});

So I want to get number of clients connected to room "CLIENT_1",

io.sockets.adapter.rooms["CLIENT_1"];

but I only get connection from current process. How can I get connection from all server processes connected through the redis adapter?

I have gone through this question:

How to check socket is alive (connected) in socket.io with multiple nodes and socket.io-redis

but it didn't help me.

Thanks for advance.

Villain answered 3/6, 2015 at 16:19 Comment(0)
A
11

As of this writing:

The redis adapter extends the base adapter, but it only overrides/adds the following properties:

  • onmessage
  • broadcast
  • add
  • del
  • delAll

With this code of yours:

io.sockets.adapter.rooms["CLIENT_1"];

you are querying the rooms property. This wasn't overridden by the redis adapter, so you're actually querying the base adapter, which only knows about rooms/clients in the current process.

Why didn't the redis adapter override the rooms property? Because in order to match the exact call signature above, it would have to query the redis instance to construct an object containing all rooms and connections every time the property is accessed. Not good. (That is unless you can figure out how to compute object values at the time their values are queried.)

If you want to get the number of connections to the "CLIENT_1" room across all processes in the cluster, you'll have to add that functionality to the adapter itself with a method like this:

/**
   * Count the number of connections in a room.
   *
   * @param {String} room id
   * @param {Function} callback (optional)
   * @api public
   */

  Redis.prototype.numClients = function(room, fn){ ... }

wherein you'll query the redis db instance.

IMO, this should be part of the base adapter interface for all other adapters to implement. It's a common problem.

Abfarad answered 22/6, 2015 at 17:50 Comment(0)
R
3

This method works perfectly:

io.sockets.adapter.clients(["room1"], function(err, clients){
  console.log("total clients in room1: %d", clients.length);
})
Rauwolfia answered 6/2, 2017 at 4:54 Comment(1)
This doesn't address the problem of running socket.io in a cluster as the OP stated it was the case.Judges
N
3

In version 7.0.0 it is possible by calling allSockets on the room. The size of the returned set is the number of connected sockets to your room on all servers in your cluster.

io.in("CLIENT_1").allSockets().then(sockets => {
  console.log("Number of clients", sockets.size)
});
Nonego answered 24/9, 2021 at 14:32 Comment(1)
This does not work in a cluster, using version 8.1.0, only works on a single instance.Sectarian
D
-1

another approach is to use the customRequest/customHook methods in socket.io-redis 3.1.0. I tried and it works. Details here. https://github.com/socketio/socket.io-redis/issues/137

Domesticate answered 5/2, 2017 at 3:46 Comment(1)
It is not very useful to say "I tried it and it works" and provide links to details elsewhere. It would be more useful for you to provide example code that you wrote where it worked for you.Sectarian

© 2022 - 2024 — McMap. All rights reserved.