确实,只要有一个客户端连接,socket.io 房间就存在。此外,一旦最后一个客户端将其作为shown here 留在套接字适配器中,它就会被销毁以释放内存:
if (this.rooms[room].length === 0) delete this.rooms[room];
要获得真实的房间名称,您必须在服务器端跟踪它们。最简单的方法是按房间名称索引的用户计数对象。
const usersByRooms = {}
当一个新的套接字连接时,你会首先发送这个完整的对象
socket.emit('getAllRooms' usersByRoom)
当你在客户端收到它时,通过它的键迭代这个对象
socket.on('getAllRooms', (usersByRoom) => {
Object.keys(usersByRoom).forEach(roomName =>
console.log(roomName, usersByRoom[roomName]))
})
我假设您的页面需要实时更新连接到您房间的客户端数量。为此,您需要一种方法来广播房间的用户数量(如果房间发生变化),并相应地更新您的usersByRooms 缓存,如下所示:
const updateCount = roomName => {
const userCount = io.sockets.clients(roomName).length
// we do not update if the count did not change
if (userCount === usersByRoom[roomName]) { return }
usersByRoom[roomName] = userCount
io.emit('updateCount', { roomName, userCount })
}
使用这两个方法的回调,每次socket加入和离开房间成功时都需要调用这个方法:
socket.join(roomName, () => {
updateCount(roomName)
})
socket.leave(roomName, () => {
updateCount(roomName)
})
您现在可以挂钩到 socket.io#2332 中添加的新 disconnecting 事件,以防您的客户端断开连接或简单地关闭您的应用程序以将新计数广播到套接字连接到的任何房间。
socket.on('disconnecting', () => {
const rooms = socket.rooms.slice()
// ...
})
这种方法可能有点棘手,因为您需要跟踪正在断开连接的套接字的房间,并在套接字完成断开连接后立即更新它们。
一个更简单的方法是在每次套接字断开连接后立即遍历所有房间并调用updateCount,因为该方法仅在房间的用户数量发生变化时广播一个事件,除非你有数以千计的房间。
socket.on('disconnected', () => {
Object.keys(usersByRooms).forEach(updateCount)
})
请注意,如果您使用的是套接字集群,它会有点棘手,但我假设是正常设置。