Socket 实例(服务器端)
Socket
是与客户端交互的基本类。它继承了 Node.js EventEmitter 的所有方法,例如 emit、on、once 或 removeListener。


除了
Socket 实例具有一些在您的应用程序中可能很有用的属性
Socket#id
每个新连接都会被分配一个随机的 20 个字符的标识符。
此标识符与客户端上的值同步。
// server-side
io.on("connection", (socket) => {
console.log(socket.id); // ojIckSD2jqNzOqIrAGzL
});
// client-side
socket.on("connect", () => {
console.log(socket.id); // ojIckSD2jqNzOqIrAGzL
});
注意
注意:您不能覆盖此标识符,因为它在 Socket.IO 代码库的多个部分中使用。
Socket#handshake
此对象包含有关 Socket.IO 会话开始时发生的握手的一些详细信息。
{
headers: /* the headers of the initial request */
query: /* the query params of the initial request */
auth: /* the authentication payload */
time: /* the date of creation (as string) */
issued: /* the date of creation (unix timestamp) */
url: /* the request URL string */
address: /* the ip of the client */
xdomain: /* whether the connection is cross-domain */
secure: /* whether the connection is secure */
}
示例
{
"headers": {
"user-agent": "xxxx",
"accept": "*/*",
"host": "example.com",
"connection": "close"
},
"query": {
"EIO": "4",
"transport": "polling",
"t": "NNjNltH"
},
"auth": {
"token": "123"
},
"time": "Sun Nov 22 2020 01:33:46 GMT+0100 (Central European Standard Time)",
"issued": 1606005226969,
"url": "/socket.io/?EIO=4&transport=polling&t=NNjNltH",
"address": "::ffff:1.2.3.4",
"xdomain": false,
"secure": true
}
Socket#rooms
这是对 Socket 当前所在的 房间 的引用。
io.on("connection", (socket) => {
console.log(socket.rooms); // Set { <socket.id> }
socket.join("room1");
console.log(socket.rooms); // Set { <socket.id>, "room1" }
});
Socket#data
可以与 fetchSockets()
实用程序方法结合使用的任意对象
// server A
io.on("connection", (socket) => {
socket.data.username = "alice";
});
// server B
const sockets = await io.fetchSockets();
console.log(sockets[0].data.username); // "alice"
更多信息 在此。
Socket#conn
对底层 Engine.IO socket 的引用(见 此处)。
io.on("connection", (socket) => {
console.log("initial transport", socket.conn.transport.name); // prints "polling"
socket.conn.once("upgrade", () => {
// called when the transport is upgraded (i.e. from HTTP long-polling to WebSocket)
console.log("upgraded transport", socket.conn.transport.name); // prints "websocket"
});
socket.conn.on("packet", ({ type, data }) => {
// called for each packet received
});
socket.conn.on("packetCreate", ({ type, data }) => {
// called for each packet sent
});
socket.conn.on("drain", () => {
// called when the write buffer is drained
});
socket.conn.on("close", (reason) => {
// called when the underlying connection is closed
});
});
其他属性
只要您不覆盖任何现有属性,您就可以将任何属性附加到 Socket 实例并在以后使用它
// in a middleware
io.use(async (socket, next) => {
try {
const user = await fetchUser(socket);
socket.user = user;
} catch (e) {
next(new Error("unknown user"));
}
});
io.on("connection", (socket) => {
console.log(socket.user);
// in a listener
socket.on("set username", (username) => {
socket.username = username;
});
});
Socket 中间件
这些中间件看起来非常像通常的 中间件,只是它们是针对每个传入数据包调用的
socket.use(([event, ...args], next) => {
// do something with the packet (logging, authorization, rate limiting...)
// do not forget to call next() at the end
next();
});
next
方法也可以使用错误对象调用。在这种情况下,事件将不会到达注册的事件处理程序,而是会发出 error
事件
io.on("connection", (socket) => {
socket.use(([event, ...args], next) => {
if (isUnauthorized(event)) {
return next(new Error("unauthorized event"));
}
next();
});
socket.on("error", (err) => {
if (err && err.message === "unauthorized event") {
socket.disconnect();
}
});
});
注意:此功能仅存在于服务器端。对于客户端,您可能对 通配符监听器 感兴趣。
事件
在服务器端,Socket 实例会发出两个特殊事件
disconnect
此事件在 Socket 实例断开连接时触发。
io.on("connection", (socket) => {
socket.on("disconnect", (reason) => {
// ...
});
});
以下是可能的理由列表
原因 | 描述 |
---|---|
服务器命名空间断开连接 | 使用 socket.disconnect() 强制断开连接。 |
客户端命名空间断开连接 | 客户端已使用 socket.disconnect() 手动断开连接。 |
服务器正在关闭 | 服务器正在关闭。 |
ping 超时 | 客户端在 pingTimeout 延迟内未发送 PONG 数据包。 |
传输关闭 | 连接已关闭(例如:用户已断开连接,或网络已从 WiFi 更改为 4G)。 |
传输错误 | 连接遇到错误。 |
解析错误 | 服务器从客户端收到了无效的数据包。 |
强制关闭 | 服务器从客户端收到了无效的数据包。 |
强制服务器关闭 | 客户端未及时加入命名空间(见 connectTimeout 选项)并被强制关闭。 |
disconnecting
此事件类似于 disconnect
,但触发时间略早,此时 Socket#rooms 集尚未为空
io.on("connection", (socket) => {
socket.on("disconnecting", (reason) => {
for (const room of socket.rooms) {
if (room !== socket.id) {
socket.to(room).emit("user has left", socket.id);
}
}
});
});
注意:这些事件以及 connect
、connect_error
、newListener
和 removeListener
是特殊事件,不应在您的应用程序中使用
// BAD, will throw an error
socket.emit("disconnect");
完整 API
可以在 此处 找到 Socket 实例公开的完整 API。