繁体   English   中英

单线检查插座是否在给定的房间?

[英]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}


特定于版本的更新:3.0+:
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'];

**更新:**
但是,只有当服务器架构具有单节点服务器/单节点进程时,才可以使用如上所述的单行检查套接字 ID 是否在给定的房间中。

如果您使用的是多节点服务器,即负载平衡的单独节点进程。

这里要注意的是,套接字只在它们第一次连接的进程上注册。 因此,您需要使用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 方法。


**更新至 5.2.0 版:(相关多节点服务器)**
现在,从 5.2.0 开始,redis 适配器为您提供跨进程/节点的空间
来源:[RedisAdapter#clients(rooms:Array, fn:Function)][5] > 返回跨所有节点连接到房间的客户端 ID 列表。 请参阅 [命名空间#clients(fn:Function)][6]
 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;

来自链接https://github.com/socketio/socket.io/issues/2890的答案

使用"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.io”:“^4.4.1”

socket.rooms.has('roomName')为我工作。
如果存在则返回true ,否则返回false

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM