跳至主要内容
版本: 4.x

房间

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

Broadcasting to all clients in a roomBroadcasting to all clients in a room
信息

请注意,房间是 仅服务器端 概念(即客户端无法访问它已加入的房间列表)。

加入和离开

您可以调用 join 将套接字订阅到给定通道

io.on("connection", (socket) => {
socket.join("some room");
});

然后在广播或发出时简单地使用 toin(它们是相同的)

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");
});

在这种情况下,房间中的每个套接字(不包括发送方)都将收到该事件。

Broadcasting to all clients in a room excepting the senderBroadcasting to all clients in a room excepting the sender

要离开通道,您可以像 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 适配器。有关它的更多信息 在此

Broadcasting to all clients in a room with RedisBroadcasting to all clients in a room with 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(...)
  • 多服务器 设置中,roomssids 对象不会在 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}`);
});