简体   繁体   English

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

[英]One-line check if socket is in given room?

I'm using Node.js with socket.io for a multiplayer card game, and there are game rooms which players can join.我正在使用 Node.js 和 socket.io 进行多人纸牌游戏,并且有玩家可以加入的游戏室。

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.对于文档,socket.io 似乎没有任何简单的方法可以做到这一点。 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 :这可以通过使用indexOf的 oneliner 来完成:

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 this您可以像这样简单地检查
io.sockets.adapter.rooms['roomId']

This returns you a object with sId eg这会返回一个带有 sId 的对象,例如
{"1sEAEIZeuMgdhF35AAAA":true}


Updates specific to versions: 3.0+: 特定于版本的更新:3.0+:
io.sockets.adapter.rooms['roomId']

1.4: 1.4:

io.sockets.adapter.rooms['roomId']; 

1.3.x: 1.3.x:

io.adapter.rooms['roomId'];

1.0.x to 1.2.x: 1.0.x 到 1.2.x:

 io.adapter.rooms['roomId'];

**Update:** **更新:**
However one can check socket Id is in a given room or not with one-line as mentioned above only if server architecture has a single node server/single node process. 但是,只有当服务器架构具有单节点服务器/单节点进程时,才可以使用如上所述的单行检查套接字 ID 是否在给定的房间中。

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.因此,您需要使用socket.io-redis将所有节点连接在一起以同步事件,并且您可以在多节点上维护套接字 Id 列表的方法是在每次客户端连接/断开连接时广播一个事件,以便每个节点更新和维护所有客户端/套接字 ID 的实时列表。

Background/Details:背景/细节:
The redis adapter extends the base adapter , but it only overrides/adds the following properties : redis 适配器扩展了基本适配器,但它只覆盖/添加了以下属性
clients broadcast add del delAll客户端广播添加 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.您正在查询 socket.io-redis 适配器上的 rooms 属性。 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.这没有被 redis 适配器覆盖,因此您实际上是在查询基本适配器,它只知道当前进程中的房间/客户端。

Why didn't the redis adapter override the rooms property?为什么 redis 适配器没有覆盖房间属性? 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.可能是因为它必须查询 redis 数据库实例来构造一个对象,该对象包含每次访问此属性时的所有房间和连接。 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.您将在其中点击 redis 数据库实例。

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 . PS 关于另一种方法的提示是使用socket.io-redis 3.1.0中的 customRequest/customHook 方法。


**Update with ver 5.2.0: (relevant multi node servers)** **更新至 5.2.0 版:(相关多节点服务器)**
Now redis adapter gives you rooms across processes/nodes as of 5.2.0 现在,从 5.2.0 开始,redis 适配器为您提供跨进程/节点的空间
Source: [RedisAdapter#clients(rooms:Array, fn:Function)][5] > Returns the list of client IDs connected to rooms across all nodes. 来源:[RedisAdapter#clients(rooms:Array, fn:Function)][5] > 返回跨所有节点连接到房间的客户端 ID 列表。 See [Namespace#clients(fn:Function)][6] 请参阅 [命名空间#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' });


Happy Coding!快乐编码!

2021 response: 2021年回应:

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() :这让我很头疼,但目前在 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 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 .这似乎在 socket.io 的版本中发生了很大变化,但在撰写本文时(版本 1.7.2),这看起来像是存储在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:在您的套接字加入任何房间之前,如文档所述,您会看到套接字已经在具有自己 ID 的房间中,因此socket.rooms看起来像:

{ 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:现在 socket.rooms 看起来像这样:

{
    "room1":"room1",
    "room2":"room2",
    ...
    "room100":"room100"
}

way to check if a socket is connected to a certain room: if(socket.rooms[roomID]) return true;检查套接字是否连接到某个房间的方法: if(socket.rooms[roomID]) return true;

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

using "socket.io": "^2.3.0" this worked for me使用"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);

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

socket.rooms.has('roomName') worked for me. socket.rooms.has('roomName')为我工作。
return true if exist other wise false如果存在则返回true ,否则返回false

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

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