房間
房間是一個任意的頻道,其中 socket 可以加入
和離開
。它可用於向部分用戶端廣播事件


資訊
請注意,房間是一個僅限伺服器的概念(即用戶端無法存取其已加入的房間清單)。
加入和離開
您可以呼叫加入
來訂閱 socket 至某個頻道
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");
在這種情況下,會執行 聯集:每個至少在其中一個房間的 Socket 都會收到事件 一次(即使 Socket 在兩個或更多房間中)。
您也可以從給定的 Socket 向房間廣播
io.on("connection", (socket) => {
socket.to("some room").emit("some event");
});
在這種情況下,房間中的每個 Socket 排除發送者都會收到事件。


若要離開頻道,請以與 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");
});
中斷連線
中斷連線後,Socket 會自動 leave
它們參與的所有頻道,您不需要特別終止。
您可以透過聆聽 disconnecting
事件來擷取 Socket 所在的房間
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 伺服器。
您只需要將預設 Adapter 替換為 Redis Adapter。有關它的更多資訊,請參閱 此處。


實作詳細資訊
「房間」功能是由我們稱為 Adapter 的功能實作。此 Adapter 是伺服器端元件,負責
- 儲存 Socket 實例與房間之間的關係
- 將事件廣播至所有(或部分)客戶端
您可以在 此處 找到預設記憶體內 Adapter 的程式碼。
基本上,它包含兩個 ES6 Map
sids
:Map<SocketId, Set<Room>>
rooms
:Map<Room, Set<SocketId>>
呼叫 socket.join("the-room")
會導致
- 在
sids
Map 中,將「the-room」新增至由 Socket ID 識別的 Set - 在
rooms
Map 中,將 socket ID 加入由字串「the-room」識別的 Set
廣播時會使用這兩個 map
- 廣播到所有 socket(
io.emit()
)會迴圈遍歷sids
Map,並將封包傳送給所有 socket - 廣播到特定房間(
io.to("room21").emit()
)會迴圈遍歷rooms
Map 中的 Set,並將封包傳送給所有符合條件的 socket
你可以使用以下方式存取這些物件
// 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
開始,基礎的 Adapter 會發出以下事件
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}`);
});