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

时间:2014-04-13 16:30:40

标签: node.js sockets

我使用带有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);
    });
});

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

if(socket with ID "z8b7dbf98i" is in room "game10")
    //do something

8 个答案:

答案 0 :(得分:10)

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

使用indexOf

可以使用oneliner完成此操作
if(socket.rooms.indexOf(room) >= 0)

或相反的搜索:

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

答案 1 :(得分:6)

您可以像这样检查 io.sockets.adapter.rooms['roomId']

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

<小时/> 特定于版本的更新:

1.4 +:

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

1.3.x中:

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

1.0.x至1.2.x:

io.adapter.rooms['roomId'];

<小时/> 的更新
但是,只有在服务器体系结构具有单节点服务器/单节点进程的情况下,才可以检查套接字ID是否在给定的空间中,如上所述仅使用单行。

如果您使用multi-node server,即使用负载平衡的单独节点进程。

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

背景/详细信息:
redis适配器扩展base adapter,但只有overrides/adds the following properties
客户 广播 加 德尔 全删除

使用以下代码:

io.sockets.adapter.rooms["roomId"]; //Any of the above examples specific to versions mentioned above

您正在查询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){ ... }

您将点击redis数据库实例。

这应该是所有其他适配器实现的基本适配器接口的一部分。这是每天每个人在扩展服务器时都会遇到的常见问题;)

P.S。只是提示另一种方法是使用 socket.io-redis 3.1.0 中的customRequest / customHook方法。

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

  

返回跨所有节点连接到房间的客户端ID列表。见Namespace#clients(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'
});


快乐的编码!

答案 2 :(得分:2)

对于当前socket.io(我认为是1.0+)io对象的结构已更改,因此您现在可以找到在给定套接字的房间中给定socketid的用户roomid

if(io.sockets.adapter.rooms[roomid][socketid])

答案 3 :(得分:1)

对于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
  }
});

答案 4 :(得分:1)

使用"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);

答案 5 :(得分:1)

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'
}

答案 6 :(得分:0)

如果你仍然需要它,你可以做下一步:

  socket.room = "someRoom";

然后简单地检查一下:

  if (socket.room !== undefined){
        socket.leave(socket.room);
  }

答案 7 :(得分:0)

现在socket.rooms看起来像这样:

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

检查插座是否连接到特定房间的方式: if(socket.rooms[roomID]) return true;

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