单行检查套接字是否在给定的房间内?

jov*_*van 11 sockets node.js

我正在使用带有socket.io的Node.js进行多人纸牌游戏,还有玩家可以加入的游戏室.

为了加入一个房间,我只需使用:

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);
    });
});
Run Code Online (Sandbox Code Playgroud)

我的问题是,检查套接字是否连接到某个房间的最快方法是什么?我知道我可以在一个数组中获取该房间中的所有套接字,然后检查目标套接字是否在数组中,但我猜测应该有更基本的语法.我正在寻找(伪代码)将是

if(socket with ID "z8b7dbf98i" is in room "game10")
    //do something
Run Code Online (Sandbox Code Playgroud)

小智 13

对于文档,socket.io似乎没有任何简单的方法来做到这一点.您确实需要检查客户端是否在房间阵列中,或者相反:如果房间在客户端阵列中.

这可以通过oneliner使用indexOf:

if(socket.rooms.indexOf(room) >= 0)
Run Code Online (Sandbox Code Playgroud)

或者相反的搜索:

if(io.sockets.manager.rooms['/' + room].indexOf(socket.id) >= 0)
Run Code Online (Sandbox Code Playgroud)

  • 这已经过时了。在撰写本文时,“socket.rooms”现在是一个键和值设置相同的对象,因此测试应该是“room in socket.rooms”或“Object.keys(socket.rooms).includes(room)” (2认同)

Amo*_*rni 7

你可以这样检查一下
io.sockets.adapter.rooms['roomId']

这会返回一个带有sId的对象,例如
{"1sEAEIZeuMgdhF35AAAA":true}


特定于版本的更新:

1.4+:

io.sockets.adapter.rooms['roomId']
Run Code Online (Sandbox Code Playgroud)

1.3.x的:

io.sockets.adapter.rooms['roomId']; 
Run Code Online (Sandbox Code Playgroud)

1.0.x到1.2.x:

io.adapter.rooms['roomId'];
Run Code Online (Sandbox Code Playgroud)


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

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

这里要注意的是,套接字仅在它们首次连接的进程上注册.因此,您需要使用socket.io-redis将所有节点连接在一起以同步事件,并且每次客户端连接/断开连接时,您可以执行的维护多节点上的套接字ID列表的事件是广播事件,以便每个节点更新并维护所有客户端/套接字ID的实时列表.

背景/详细信息:
redis适配器扩展了基本适配器,但它只覆盖/添加以下属性:
clients broadcast add del delAll

使用以下代码:

io.sockets.adapter.rooms["roomId"]; //Any of the above examples specific to versions mentioned above
Run Code Online (Sandbox Code Playgroud)

你在socket.io-redis适配器上查询房间属性.这没有被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){ ... }
Run Code Online (Sandbox Code Playgroud)

你将在哪里点击redis数据库实例.

这应该是所有其他适配器实现的基本适配器接口的一部分.当他们扩展服务器时,每天都会遇到一个普遍的问题;)

PS只是提示另一种方法是在socket.io-redis 3.1.0中使用customRequest/customHook方法.


使用ver 5.2.0进行更新:(相关的多节点服务器)
现在,从5.2.0开始,redis适配器为您提供跨进程/节点的空间
源:RedisAdapter#clients(rooms:Array,fn:Function)

返回跨所有节点连接到房间的客户端ID列表.请参阅命名空间#客户端(fn:Function)

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'
});
Run Code Online (Sandbox Code Playgroud)


快乐的编码!


Jim*_*aro 5

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'
}
Run Code Online (Sandbox Code Playgroud)

如果您需要检查用户是否不在房间内,您可以简单地使用!

if (!socket.rooms.has('abc')) {
  // Do something if socket is NOT in room 'abc'
}
Run Code Online (Sandbox Code Playgroud)