[英]One-line check if socket is in given room?
我正在使用 Node.js 和 socket.io 进行多人纸牌游戏,并且有玩家可以加入的游戏室。
要加入一个房间,我只需使用:
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);
});
});
我的问题是,检查插座是否连接到某个房间的最快方法是什么? 我知道我可以在一个数组中获取那个房间中的所有套接字,然后检查目标套接字是否在数组中,但我猜应该有一个更基本的语法。 我正在寻找的(在伪代码中)将是
if(socket with ID "z8b7dbf98i" is in room "game10")
//do something
对于文档,socket.io 似乎没有任何简单的方法可以做到这一点。 您确实需要检查客户端是否在房间数组中,或者相反:房间是否在客户端数组中。
这可以通过使用indexOf
的 oneliner 来完成:
if(socket.rooms.indexOf(room) >= 0)
或相反的搜索:
if(io.sockets.manager.rooms['/' + room].indexOf(socket.id) >= 0)
您可以像这样简单地检查io.sockets.adapter.rooms['roomId']
这会返回一个带有 sId 的对象,例如{"1sEAEIZeuMgdhF35AAAA":true}
io.sockets.adapter.rooms['roomId']
1.4:
io.sockets.adapter.rooms['roomId'];
1.3.x:
io.adapter.rooms['roomId'];
1.0.x 到 1.2.x:
io.adapter.rooms['roomId'];
如果您使用的是多节点服务器,即负载平衡的单独节点进程。
这里要注意的是,套接字只在它们第一次连接的进程上注册。 因此,您需要使用socket.io-redis将所有节点连接在一起以同步事件,并且您可以在多节点上维护套接字 Id 列表的方法是在每次客户端连接/断开连接时广播一个事件,以便每个节点更新和维护所有客户端/套接字 ID 的实时列表。
背景/细节:
redis 适配器扩展了基本适配器,但它只覆盖/添加了以下属性:
客户端广播添加 del delAll
使用以下代码:
io.sockets.adapter.rooms["roomId"]; //Any of the above examples specific to versions mentioned above
您正在查询 socket.io-redis 适配器上的 rooms 属性。 这没有被 redis 适配器覆盖,因此您实际上是在查询基本适配器,它只知道当前进程中的房间/客户端。
为什么 redis 适配器没有覆盖房间属性? 可能是因为它必须查询 redis 数据库实例来构造一个对象,该对象包含每次访问此属性时的所有房间和连接。 不是个好主意?
因此,在撰写本文时,您必须使用以下方法将该功能添加到适配器本身:
/** * 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){ ... }
您将在其中点击 redis 数据库实例。
这应该是所有其他适配器要实现的基本适配器接口的一部分。 这是每个人在扩展服务器时都会面临的一个常见问题;)
PS 关于另一种方法的提示是使用socket.io-redis 3.1.0中的 customRequest/customHook 方法。
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' });
快乐编码!
2021年回应:
这让我很头疼,但目前在 Socket IO 的4.0.2 版本中, socket.rooms
是一个 Javascript Set
,因此您可以使用.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 (!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])
这似乎在 socket.io 的版本中发生了很大变化,但在撰写本文时(版本 1.7.2),这看起来像是存储在socket.rooms
中。 这是一个看起来像这样的对象:
{
room_name: 'room_name',
second_room_name: 'second_room_name',
...
}
在您的套接字加入任何房间之前,如文档所述,您会看到套接字已经在具有自己 ID 的房间中,因此socket.rooms
看起来像:
{ PxtiIs22S7GhWPTSAAAA: 'PxtiIs22S7GhWPTSAAAA'}
这意味着您可以检查一个插座是否在房间中,如下所示:
io.on('connection', function(socket){
if(socket.rooms[myRoomName]){
// in the room
}else{
// not in the room
}
});
现在 socket.rooms 看起来像这样:
{
"room1":"room1",
"room2":"room2",
...
"room100":"room100"
}
检查套接字是否连接到某个房间的方法: if(socket.rooms[roomID]) return true;
使用"socket.io": "^2.3.0"
这对我有用
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);
如果您仍然需要它,您可以执行以下操作:
socket.room = "someRoom";
然后简单地检查它:
if (socket.room !== undefined){
socket.leave(socket.room);
}
socket.rooms.has('roomName')
为我工作。
如果存在则返回true
,否则返回false
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.