Socket IO Rooms:获取特定房间的客户端列表
Posted
技术标签:
【中文标题】Socket IO Rooms:获取特定房间的客户端列表【英文标题】:Socket IO Rooms: Get list of clients in specific room 【发布时间】:2013-08-08 06:06:02 【问题描述】:我正在尝试显示特定房间中的客户列表。我只想显示他们的用户名,而不是他们的套接字 ID。
我现在的位置:
socket.set('nickname', "Earl");
socket.join('chatroom1');
console.log('User joined chat room 1);
var roster = io.sockets.clients('chatroom1');
for ( i in roster )
console.log('Username: ' + roster[i]);
没有任何运气让它列出套接字 ID 或任何东西。但是希望它返回昵称。
【问题讨论】:
【参考方案1】:在 socket.IO 3.x 中
New to version 3.x is that connected is renamed to sockets and is now an ES6 Map on namespaces. 在房间的套接字上是一个 ES6 客户端 ID 集。
//this is an ES6 Set of all client ids in the room
const clients = io.sockets.adapter.rooms.get('Room Name');
//to get the number of clients in this room
const numClients = clients ? clients.size : 0;
//to just emit the same event to all members of a room
io.to('Room Name').emit('new event', 'Updates');
for (const clientId of clients )
//this is the socket of each client in the room.
const clientSocket = io.sockets.sockets.get(clientId);
//you can do whatever you need with this
clientSocket.leave('Other Room')
在 socket.IO 1.x 到 2.x 中
请参考以下答案: Get list of all clients in specific room。复制如下,稍作修改:
const clients = io.sockets.adapter.rooms['Room Name'].sockets;
//to get the number of clients in this room
const numClients = clients ? Object.keys(clients).length : 0;
//to just emit the same event to all members of a room
io.to('Room Name').emit('new event', 'Updates');
for (const clientId in clients )
//this is the socket of each client in the room.
const clientSocket = io.sockets.connected[clientId];
//you can do whatever you need with this
clientSocket.leave('Other Room')
【讨论】:
我需要 > 1.0 的东西,但是你清楚地表明这不适用于上面的 1.0,没有理由反对。有一个 +1 来平衡它:p。【参考方案2】:不要深入socket/io
对象,你可以使用简单而标准的方式:
io.in(room_name).clients((err , clients) =>
// clients will be array of socket ids , currently available in given room
);
更多详情DO READ
【讨论】:
如何使用 async 和 await ? 请注意,此解决方案不适用于 socket.IO v3 或更高版本。【参考方案3】:只是一些事情。
当您拥有socket
后,您可以设置如下属性:socket.nickname = 'Earl';
稍后在控制台日志中使用 save 属性:
console.log(socket.nickname);
您的:
console.log('User joined chat room 1);
我不完全确定你的循环。
下面是修改后的代码应该可以帮助你一点,还要注意我在下面使用的循环是异步的,这可能会影响你处理数据传输的方式。
socket.nickname = 'Earl';
socket.join('chatroom1');
console.log('User joined chat room 1');
var roster = io.sockets.clients('chatroom1');
roster.forEach(function(client)
console.log('Username: ' + client.nickname);
);
为了帮助你更多,我需要查看你所有的代码,因为这没有给我上下文。
【讨论】:
“io.sockets.clients('chatroom1')”在 nodejs v1.0 及更高版本中工作吗? 您好,我在io.sockets.clients('roomname')中遇到错误,mysocket版本是2.2.0 虽然这是公认的答案,但它不适用于高于 socket.io 1.0 的版本。 这个方法不存在了 方法给出错误:客户端不是函数【参考方案4】:对于 v4,我使用了这个方法 fetchSockets()
例子:
let roomUsers=await io.in(`room-id`).fetchSockets()
在此处查看文档: https://socket.io/docs/v3/migrating-from-3-x-to-4-0/#Additional-utility-methods
【讨论】:
【参考方案5】:如果您使用 2.0,上述所有答案以及此处 socket.io get rooms which socket is currently in 或此处 Socket.IO - how do I get a list of connected sockets/clients? 的答案要么不正确要么不完整。
-
在 2.0 中,
io.sockets.manager
和 io.sockets.clients
不再存在。
不使用命名空间,以下3个参数都可以获取特定房间的sockets。
socket.adapter.rooms;
io.sockets.adapter.rooms;
io.sockets.adapter.sids; // the socket.id array
有了命名空间(我在这里使用了“cs”),io.sockets.adapter.rooms
会给出一个相当混乱的结果,而socket.adapter.rooms
给出的结果是正确的:
/* socket.adapter.rooms give: */
"/cs#v561bgPlss6ELZIZAAAB":
"sockets":
"/cs#v561bgPlss6ELZIZAAAB": true
,
"length": 1
,
"a room xxx": "sockets":
"/cs#v561bgPlss6ELZIZAAAB": true
,
"length": 1
/* io.sockets.adapter.rooms give: a sid without namespace*/
"v561bgPlss6ELZIZAAAB":
"sockets":
"v561bgPlss6ELZIZAAAB": true
, "length": 1
注意:默认房间是这样的:“Each Socket in Socket.IO is identified by a random, unguessable, unique identifier Socket#id. For your convenience, each socket automatically joins a room identified by this id。”
目前只尝试过内存适配器,没有尝试过redis-adapter。
【讨论】:
【参考方案6】:对于socket.IO v3
,这里有一个重大更改:
Namespace.clients() 重命名为 Namespace.allSockets(),现在返回一个 Promise。
之前:
// all sockets in the "chat" namespace and in the "general" room
io.of("/chat").in("general").clients((error, clients) =>
console.log(clients); // => [Anw2LatarvGVVXEIAAAD]
);
现在 (v3):
// all sockets in the "chat" namespace and in the "general" room
const ids = await io.of("/chat").in("general").allSockets();
Source
如果您对 socket.IO 不太熟悉,最好知道您可以编写 io
来代替 io.of("/chat")
来使用默认命名空间。
【讨论】:
这也适用于 Socket.IO v4。准确地说,上面的示例代码返回的是一组套接字 ID,而不是实际的 Socket 对象。io.of('/').sockets
可用于获取连接到命名空间的 Socket 实例的 Map,因此 io.of('/').sockets.get(socketId)
获取与 id 匹配的 Socket 实例。【参考方案7】:
socket.io ^ 2.0
function getRoomClients(room)
return new Promise((resolve, reject) =>
io.of('/').in(room).clients((error, clients) =>
resolve(clients);
);
);
...
const clients = await getRoomClients('hello-world');
console.log(clients);
输出
[ '9L47TWua75nkL_0qAAAA',
'tVDBzLjhPRNdgkZdAAAB',
'fHjm2kxKWjh0wUAKAAAC' ]
【讨论】:
【参考方案8】:对于大于 v1.0 的 Socket.io 和节点 v6.0+ 使用以下代码:
function getSockets(room) // will return all sockets with room name
return Object.entries(io.sockets.adapter.rooms[room] === undefined ?
: io.sockets.adapter.rooms[room].sockets )
.filter(([id, status]) => status) // get only status = true sockets
.map(([id]) => io.sockets.connected[id])
如果你想向他们发射一些东西,使用这个:
getSockets('room name').forEach(socket => socket.emit('event name', data))
【讨论】:
【参考方案9】:从 Socket.io v3 开始,rooms
现在是 Adapter
的受保护属性,因此您将无法通过 io.sockets.adapter.rooms
访问它。
改为使用:
const clientsInRoom = await io.in(roomName).allSockets()
OR 用于多个房间
const clientsInRooms = await io.sockets.adapter.sockets(new Set([roomName, roomName2]))
【讨论】:
【参考方案10】:对于 Socket v.4,正确的语法是:
const sockets = await io.in("room1").fetchSockets();
https://socket.io/docs/v4/server-api/#namespacefetchsockets
【讨论】:
【参考方案11】:我刚刚将房间中的所有套接字都记录到控制台,你可以对它们做任何你喜欢的事情......
const socketsInRoom = io.adapter.rooms[room_name];
/*Collect all participants in room*/
for(let participant in socketsInRoom)
for(let socketId in socketsInRoom[participant])
console.log(socketId)
【讨论】:
【参考方案12】:您可以在 io 对象上使用适配器方法,例如
io.sockets.adapter.rooms.get("chatroom1")
这将返回特定房间中已连接客户端的列表。 io.sockets.adapter.rooms 这是连接到房间的所有客户端的映射,房间名称作为键,连接的客户端是房间键的值。地图功能适用。
【讨论】:
【参考方案13】:socket.io ^2.2.0
const socket = io(url)
socket.on('connection', client =>
socket.of('/').in("some_room_name").clients((err, clients) =>
console.log(clients) // an array of socket ids
)
)
【讨论】:
我怎样才能使用 async 和 await 呢? 一个简单的答案是将整个事情包装在一个异步函数中并等待回调。这可能会有所帮助:***.com/questions/47035243/…【参考方案14】:此解决方案适用于
socket.io:“3.0.4” socket.io-redis:“6.0.1”先导入这些
const redis = require('socket.io-redis');
io.adapter(redis( host: 'localhost', port: 6379 ));
socket.on('create or join', function(room)
log('Received request to create or join room ' + room);
//var clientsInRoom = io.sockets.adapter.rooms[room];
mapObject = io.sockets.adapter.rooms // return Map Js Object
clientsInRoom = new Set(mapObject.get(room))
var numClients = clientsInRoom ? clientsInRoom.size : 0;
log('Room ' + room + ' now has ' + numClients + ' client(s)');
https://socket.io/docs/v3/using-multiple-nodes/#The-Redis-adapter https://developer.mozilla.org/en-US/docs/Web/javascript/Reference/Global_Objects/Map/get
【讨论】:
【参考方案15】:由于我几乎没有找到关于如何在特定命名空间中获取房间的信息,所以在这里以防万一有人想知道:
io.of(namespaceName).adapter.rooms;
【讨论】:
【参考方案16】:您可以将用户集合的数组对象创建为
var users = ;
然后在服务器端,您可以在连接时将其添加为新用户
socket.on('new-user', function (username)
users[username] = username;
);
在显示用户时,您可以循环“用户”对象
在客户端
var socket = io.connect();
socket.on('connect', function ()
socket.emit('new-user', 'username');
);
【讨论】:
说真的,您要从客户端发送用户名而不是检查 cookie 和其他东西?是不是很容易伪造? 我建议使用带有中间件的 socket.handshake.query 进行身份验证,然后将该令牌/用户名存储为套接字属性以从服务器端引用,这样它就可以正常工作了。以上是关于Socket IO Rooms:获取特定房间的客户端列表的主要内容,如果未能解决你的问题,请参考以下文章