伺服器實例
伺服器實例(在程式碼範例中通常稱為 io
)有一些屬性,可能對應用程式有用。
它也繼承了 主名稱空間 的所有方法,例如 namespace.use()
(請參閱 此處)或 namespace.allSockets()
。
Server#engine
對應的 Engine.IO 伺服器。
可用於取得目前已連線用戶端數目
const count = io.engine.clientsCount;
// may or may not be similar to the count of Socket instances in the main namespace, depending on your usage
const count2 = io.of("/").sockets.size;
或產生自訂的會話 ID(sid
查詢參數)
const uuid = require("uuid");
io.engine.generateId = (req) => {
return uuid.v4(); // must be unique across all Socket.IO servers
}
自 socket.io@4.1.0
起,Engine.IO 伺服器會發出三個特殊事件
initial_headers
:會在寫入階段的第一個 HTTP 要求(握手)的回應標頭之前發出,允許您自訂它們。
io.engine.on("initial_headers", (headers, req) => {
headers["test"] = "123";
headers["set-cookie"] = "mycookie=456";
});
headers
:會在寫入階段的每個 HTTP 要求(包括 WebSocket 升級)的回應標頭之前發出,允許您自訂它們。
io.engine.on("headers", (headers, req) => {
headers["test"] = "789";
});
connection_error
:會在連線異常關閉時發出
io.engine.on("connection_error", (err) => {
console.log(err.req); // the request object
console.log(err.code); // the error code, for example 1
console.log(err.message); // the error message, for example "Session ID unknown"
console.log(err.context); // some additional error context
});
以下是可能的錯誤代碼清單
代碼 | 訊息 |
---|---|
0 | "傳輸不明" |
1 | "階段 ID 不明" |
2 | "錯誤的握手方法" |
3 | "錯誤的請求" |
4 | "禁止" |
5 | "不支援的協定版本" |
實用方法
Socket.IO v4.0.0 中新增了一些實用方法來管理 Socket 實例及其房間
socketsJoin
:讓符合條件的 Socket 實例加入指定的房間socketsLeave
:讓符合條件的 Socket 實例離開指定的房間disconnectSockets
:讓符合條件的 Socket 實例中斷連線fetchSockets
:傳回符合條件的 Socket 實例
Socket.IO v4.1.0 中新增了 serverSideEmit
方法。
這些方法與廣播共享相同的語意,並套用相同的篩選條件
io.of("/admin").in("room1").except("room2").local.disconnectSockets();
這會讓 "admin" 名稱空間的所有 Socket 實例
- 在 "room1" 房間中(
in("room1")
或to("room1")
) - 除了 "room2" 中的那些(
except("room2")
) - 且僅在目前的 Socket.IO 伺服器(
local
)上
中斷連線。
請注意,它們也與 Redis 介面卡相容(從 socket.io-redis@6.1.0
開始),這表示它們會在 Socket.IO 伺服器間運作。
socketsJoin
此方法讓符合條件的 Socket 實例加入指定的房間
// make all Socket instances join the "room1" room
io.socketsJoin("room1");
// make all Socket instances in the "room1" room join the "room2" and "room3" rooms
io.in("room1").socketsJoin(["room2", "room3"]);
// make all Socket instances in the "room1" room of the "admin" namespace join the "room2" room
io.of("/admin").in("room1").socketsJoin("room2");
// this also works with a single socket ID
io.in(theSocketId).socketsJoin("room1");
socketsLeave
此方法讓符合條件的 Socket 實例離開指定的房間
// make all Socket instances leave the "room1" room
io.socketsLeave("room1");
// make all Socket instances in the "room1" room leave the "room2" and "room3" rooms
io.in("room1").socketsLeave(["room2", "room3"]);
// make all Socket instances in the "room1" room of the "admin" namespace leave the "room2" room
io.of("/admin").in("room1").socketsLeave("room2");
// this also works with a single socket ID
io.in(theSocketId).socketsLeave("room1");
disconnectSockets
此方法會使相符的 Socket 執行個體中斷連線
// make all Socket instances disconnect
io.disconnectSockets();
// make all Socket instances in the "room1" room disconnect (and discard the low-level connection)
io.in("room1").disconnectSockets(true);
// make all Socket instances in the "room1" room of the "admin" namespace disconnect
io.of("/admin").in("room1").disconnectSockets();
// this also works with a single socket ID
io.of("/admin").in(theSocketId).disconnectSockets();
fetchSockets
此方法會傳回相符的 Socket 執行個體
// return all Socket instances of the main namespace
const sockets = await io.fetchSockets();
// return all Socket instances in the "room1" room of the main namespace
const sockets = await io.in("room1").fetchSockets();
// return all Socket instances in the "room1" room of the "admin" namespace
const sockets = await io.of("/admin").in("room1").fetchSockets();
// this also works with a single socket ID
const sockets = await io.in(theSocketId).fetchSockets();
上述範例中的 sockets
變數是物件陣列,會公開 Socket 類別的子集
for (const socket of sockets) {
console.log(socket.id);
console.log(socket.handshake);
console.log(socket.rooms);
console.log(socket.data);
socket.emit(/* ... */);
socket.join(/* ... */);
socket.leave(/* ... */);
socket.disconnect(/* ... */);
}
data
屬性是任意的物件,可用於在 Socket.IO 伺服器之間共用資訊
// server A
io.on("connection", (socket) => {
socket.data.username = "alice";
});
// server B
const sockets = await io.fetchSockets();
console.log(sockets[0].data.username); // "alice"
serverSideEmit
此方法允許在叢集的其它 Socket.IO 伺服器上發出事件,在 多伺服器設定 中。
語法
io.serverSideEmit("hello", "world");
而在接收端
io.on("hello", (arg1) => {
console.log(arg1); // prints "world"
});
也支援確認
// server A
io.serverSideEmit("ping", (err, responses) => {
console.log(responses[0]); // prints "pong"
});
// server B
io.on("ping", (cb) => {
cb("pong");
});
注意事項
connection
、connect
和new_namespace
字串是保留字,且無法在您的應用程式中使用。您可以傳送任意數量的引數,但目前不支援二進制結構(引數陣列將會被
JSON.stringify
化)
範例
io.serverSideEmit("hello", "world", 1, "2", { 3: "4" });
- 如果其它 Socket.IO 伺服器在特定延遲後沒有回應,則確認呼叫回函可能會帶有錯誤
io.serverSideEmit("ping", (err, responses) => {
if (err) {
// at least one Socket.IO server has not responded
// the 'responses' array contains all the responses already received though
} else {
// success! the 'responses' array contains one object per other Socket.IO server in the cluster
}
});
事件
Server 執行個體會發出單一事件(技術上來說是兩個,但 connect
是 connection
的別名)
connection
此事件會在建立新連線時觸發。第一個引數是 Socket 執行個體。
io.on("connection", (socket) => {
// ...
});
完整 API
Server 執行個體公開的完整 API 可以在此處找到 here。