I'm using Node.js with socket.io for a multiplayer card game, and there are game rooms which players can join.
For joining a room, I simply use:
io.sockets.on('connection', function (socket) {
socket.on('joinRoom', function (gid) {
//gid is game ID - create room name based on this and join the room
var room = 'game'+gid;
socket.join(room);
});
});
My question is, what is the quickest way to check if a socket is connected to a certain room? I know I could get all sockets in that room in an array and then check whether the target socket is in the array, but I'm guessing there should be a more basic syntax for this. What I'm looking for (in pseudo-code) would be
if(socket with ID "z8b7dbf98i" is in room "game10")
//do something
For the documentation, socket.io doesn't seem to have any simple way to do that. You really need to check if the client is in the room array, or the opposite: if the room is in the client array.
This can be done with an oneliner using indexOf
:
if(socket.rooms.indexOf(room) >= 0)
Or the opposite search:
if(io.sockets.manager.rooms['/' + room].indexOf(socket.id) >= 0)
You can simply check like thisio.sockets.adapter.rooms['roomId']
This returns you a object with sId eg{"1sEAEIZeuMgdhF35AAAA":true}
io.sockets.adapter.rooms['roomId']
1.4:
io.sockets.adapter.rooms['roomId'];
1.3.x:
io.adapter.rooms['roomId'];
1.0.x to 1.2.x:
io.adapter.rooms['roomId'];
If you are using multi-node server , ie separate node process with load balanced.
Point to note here is, that the sockets are only registered on the process that they first connected to. So, you need to use socket.io-redis to connect all your nodes together to sync events, and what you can do to maintain list of socket Ids across multi-node is broadcast an event each time a client connects/disconnects, so that each node updates & maintains the real-time list of all the clients/socket Ids.
Background/Details:
The redis adapter extends the base adapter , but it only overrides/adds the following properties :
clients broadcast add del delAll
With the following code:
io.sockets.adapter.rooms["roomId"]; //Any of the above examples specific to versions mentioned above
you are querying the rooms property on socket.io-redis adapter. 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? Might be because it would have to query the redis database instance to construct an object containing all rooms and connections on every access of this property. Not a good idea?
So as of this writing answer, you'll have to add that functionality to the adapter itself with a method like this:
/** * One-Line code/property to check if the socket id is in given room. * * @param {String} room id * @param {Function} callback (optional) * @api public */ Redis.prototype.isSidExistsInRoom = function(room, fn){ ... }
where you will hit the redis database instance.
This should be part of the base adapter interface for all other adapters to implement. It's a common problem everyone will face one day, when they scale their servers ;)
PS Just a hint on another approach is to use the customRequest/customHook methods in socket.io-redis 3.1.0 .
io.of('/').adapter.clients((err, clients) => { console.log(clients); // an array containing all connected socket ids }); io.of('/').adapter.clients(['room1', 'room2'], (err, clients) => { console.log(clients); // an array containing socket ids in 'room1' and/or 'room2' }); // you can also use io.in('room3').clients((err, clients) => { console.log(clients); // an array containing socket ids in 'room3' });
Happy Coding!
2021 response:
This was such a headache for me, but currently in version 4.0.2 of Socket IO, socket.rooms
is a Javascript Set
, so you can check if the given socket is in the room using .has()
:
if (socket.rooms.has('abc')) {
// Do something if socket is in room 'abc'
} else {
// Do something if socket is NOT in room 'abc'
}
If you need to check if the user is not in the room, you can simply use !
:
if (!socket.rooms.has('abc')) {
// Do something if socket is NOT in room 'abc'
}
对于当前的socket.io
(我想是 1.0+), io
对象的结构已更改,因此您现在可以通过以下方式找出房间中是否存在具有给定socketid
的用户和给定的 socket roomid
:
if(io.sockets.adapter.rooms[roomid][socketid])
This seems to have changed quite a lot with versions of socket.io, but as of this writing (version 1.7.2), this looks like it's stored in socket.rooms
. It's an object that looks like this:
{
room_name: 'room_name',
second_room_name: 'second_room_name',
...
}
Before your socket has joined any rooms, as documented, you'll see that the socket is already in a room with it's own id, so socket.rooms
will look something like:
{ PxtiIs22S7GhWPTSAAAA: 'PxtiIs22S7GhWPTSAAAA'}
That means you can check if a socket is in a room something like this:
io.on('connection', function(socket){
if(socket.rooms[myRoomName]){
// in the room
}else{
// not in the room
}
});
now socket.rooms looks like that:
{
"room1":"room1",
"room2":"room2",
...
"room100":"room100"
}
way to check if a socket is connected to a certain room: if(socket.rooms[roomID]) return true;
answers from link https://github.com/socketio/socket.io/issues/2890
using "socket.io": "^2.3.0"
this worked for me
if (!(io.sockets.adapter.rooms[room] && io.sockets.adapter.rooms[room].sockets[socket.id]))
// Join room or do any stuff
socket.join('product_' + product_id);
If you still need it you can do next:
socket.room = "someRoom";
and then simply check it:
if (socket.room !== undefined){
socket.leave(socket.room);
}
socket.rooms.has('roomName')
worked for me.
return true
if exist other wise false
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.