房间
房间 是一个任意通道,套接字可以 加入
和 离开
。它可以用来向客户端子集广播事件


信息
请注意,房间是 仅服务器端 概念(即客户端无法访问它已加入的房间列表)。
加入和离开
您可以调用 join
将套接字订阅到给定通道
io.on("connection", (socket) => {
socket.join("some room");
});
然后在广播或发出时简单地使用 to
或 in
(它们是相同的)
io.to("some room").emit("some event");
或排除一个房间
io.except("some room").emit("some event");
您也可以同时向多个房间发出
io.to("room1").to("room2").to("room3").emit("some event");
在这种情况下,将执行 并集:至少在一个房间中的每个套接字都将收到该事件 一次(即使套接字在两个或多个房间中)。
您也可以从给定套接字向房间广播
io.on("connection", (socket) => {
socket.to("some room").emit("some event");
});
在这种情况下,房间中的每个套接字(不包括发送方)都将收到该事件。


要离开通道,您可以像 join
一样调用 leave
。
示例用例
- 将数据广播到给定用户的每个设备/选项卡
function computeUserIdFromHeaders(headers) {
// to be implemented
}
io.on("connection", async (socket) => {
const userId = await computeUserIdFromHeaders(socket.handshake.headers);
socket.join(userId);
// and then later
io.to(userId).emit("hi");
});
- 发送有关给定实体的通知
io.on("connection", async (socket) => {
const projects = await fetchProjects(socket);
projects.forEach(project => socket.join("project:" + project.id));
// and then later
io.to("project:4321").emit("project updated");
});
断开连接
断开连接后,套接字会自动 离开
它们所属的所有通道,您无需进行任何特殊的拆卸操作。
您可以通过监听 disconnecting
事件来获取套接字所在的房间
io.on("connection", socket => {
socket.on("disconnecting", () => {
console.log(socket.rooms); // the Set contains at least the socket ID
});
socket.on("disconnect", () => {
// socket.rooms.size === 0
});
});
使用多个 Socket.IO 服务器
与 全局广播 一样,向房间广播也适用于多个 Socket.IO 服务器。
您只需要将默认的 适配器 替换为 Redis 适配器。有关它的更多信息 在此。


实现细节
"房间" 功能由我们称为适配器的组件实现。此适配器是服务器端组件,负责
- 存储套接字实例与房间之间的关系
- 将事件广播到所有(或部分)客户端
您可以在 此处 找到默认内存中适配器的代码。
基本上,它包含两个 ES6 地图
sids
:Map<SocketId, Set<Room>>
rooms
:Map<Room, Set<SocketId>>
调用 socket.join("the-room")
将导致
- 在
sids
地图中,将 "the-room" 添加到由套接字 ID 标识的集合中 - 在
rooms
地图中,将套接字 ID 添加到由字符串 "the-room" 标识的集合中
然后在广播时使用这两个地图
- 向所有套接字广播 (
io.emit()
) 将循环遍历sids
地图,并将数据包发送到所有套接字 - 向给定房间广播 (
io.to("room21").emit()
) 将循环遍历rooms
地图中的集合,并将数据包发送到所有匹配的套接字
您可以使用以下方法访问这些对象
// main namespace
const rooms = io.of("/").adapter.rooms;
const sids = io.of("/").adapter.sids;
// custom namespace
const rooms = io.of("/my-namespace").adapter.rooms;
const sids = io.of("/my-namespace").adapter.sids;
注意
- 这些对象不应直接修改,您应该始终使用
socket.join(...)
和socket.leave(...)
。 - 在 多服务器 设置中,
rooms
和sids
对象不会在 Socket.IO 服务器之间共享(房间可能只在其中一台服务器上 "存在",而不在其他服务器上)。
房间事件
从 socket.io@3.1.0
开始,底层适配器将发出以下事件
create-room
(参数:房间)delete-room
(参数:房间)join-room
(参数:房间,id)leave-room
(参数:房间,id)
示例
io.of("/").adapter.on("create-room", (room) => {
console.log(`room ${room} was created`);
});
io.of("/").adapter.on("join-room", (room, id) => {
console.log(`socket ${id} has joined room ${room}`);
});