服务器实例
The Server instance (often called io
in the code examples) has a few attributes that may be of use in your application.
It also inherits all the methods of the main namespace, like namespace.use()
(see here) or namespace.allSockets()
.
Server#engine
A reference to the underlying Engine.IO server.
It can be used to fetch the number of currently connected clients:
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;
Or to generate a custom session ID (the sid
query parameter):
const uuid = require("uuid");
io.engine.generateId = (req) => {
return uuid.v4(); // must be unique across all Socket.IO servers
}
As of socket.io@4.1.0
, the Engine.IO server emits three special events:
initial_headers
: will be emitted just before writing the response headers of the first HTTP request of the session (the handshake), allowing you to customize them.
io.engine.on("initial_headers", (headers, req) => {
headers["test"] = "123";
headers["set-cookie"] = "mycookie=456";
});
headers
: will be emitted just before writing the response headers of each HTTP request of the session (including the WebSocket upgrade), allowing you to customize them.
io.engine.on("headers", (headers, req) => {
headers["test"] = "789";
});
connection_error
: will be emitted when a connection is abnormally closed
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
});
Here is the list of possible error codes:
Code | Message |
---|---|
0 | "Transport unknown" |
1 | "Session ID unknown" |
2 | "Bad handshake method" |
3 | "Bad request" |
4 | "Forbidden" |
5 | "Unsupported protocol version" |
Utility methods
Some utility methods were added in Socket.IO v4.0.0 to manage the Socket instances and their rooms:
socketsJoin
: makes the matching socket instances join the specified rooms- ̀
socketsLeave
: makes the matching socket instances leave the specified rooms disconnectSockets
: makes the matching socket instances disconnectfetchSockets
: returns the matching socket instances
The serverSideEmit
method was added in Socket.IO v4.1.0.
Those methods share the same semantics as broadcasting, and the same filters apply:
io.of("/admin").in("room1").except("room2").local.disconnectSockets();
Which makes all Socket instances of the "admin" namespace
- in the "room1" room (
in("room1")
orto("room1")
) - except the ones in "room2" (
except("room2")
) - and only on the current Socket.IO server (
local
)
disconnect.
Please note that they are also compatible with the Redis adapter (starting with socket.io-redis@6.1.0
), which means that they will work across Socket.IO servers.
socketsJoin
This method makes the matching Socket instances join the specified rooms:
// 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
This method makes the matching Socket instances leave the specified rooms:
// 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
This method makes the matching Socket instances disconnect:
// 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
This method returns the matching Socket instances:
// 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();
The sockets
variable in the example above is an array of objects exposing a subset of the usual Socket class:
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(/* ... */);
}
The data
attribute is an arbitrary object that can be used to share information between Socket.IO servers:
// 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
This method allows to emit events to the other Socket.IO servers of the cluster, in a multi-server setup.
Syntax:
io.serverSideEmit("hello", "world");
And on the receiving side:
io.on("hello", (arg1) => {
console.log(arg1); // prints "world"
});
Acknowledgements are supported too:
// server A
io.serverSideEmit("ping", (err, responses) => {
console.log(responses[0]); // prints "pong"
});
// server B
io.on("ping", (cb) => {
cb("pong");
});
Notes:
the
connection
,connect
andnew_namespace
strings are reserved and cannot be used in your application.you can send any number of arguments, but binary structures are currently not supported (the array of arguments will be
JSON.stringify
-ed)
Example:
io.serverSideEmit("hello", "world", 1, "2", { 3: "4" });
- the acknowledgement callback might be called with an error, if the other Socket.IO servers do not respond after a given delay
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
}
});
Events
The Server instance emits one single event (well, technically two, but connect
is an alias for connection
):
connection
This event is fired upon a new connection. The first argument is a Socket instance.
io.on("connection", (socket) => {
// ...
});
Complete API
The complete API exposed by the Server instance can be found here.