持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第1天,点击查看活动详情
Demo 截图:
Demo 源码地址:github.com/goblin-labo…
文档地址:socket.io/docs/v4/
概念
-
定义
Socket.IO 是一个可以在客户端和服务器之间实现低延迟、双向和基于事件的通信库。
基于事件体现在以下几点:
- Server/Client 端发送消息使用
emit接口
- 接收消息通过
on接口进行订阅
- 客户端如果不订阅消息,Server 端即使调用了
emit接口发送消息,实际是不会产生消息发送的
-
特性
它建立在WebSocket协议之上,并提供额外的保证,例如回退到 HTTP 长轮询或自动重新连接。
- 默认使用 WebSocket 进行传输,如果客户端不支持,自动回退到 HTTP 长轮询
- 默认包含 ping/pong 机制,定期检查连接状态
- 自动重新连接,连接断开后自动重连,重连期间的消息会被缓存起来,并在重新连接后发送
- 支持广播,msg-sync 中是自己去遍历 socket 实现的
- 支持 namespace 和 room,文档位置 socket.io/docs/v4/nam… ,msg-sync 中也是通过自己过滤来实现的
-
注意事项
Socket.IO 不是 WebSocket
Socket.IO 不是 WebSocket
Socket.IO 不是 WebSocket
尽管 Socket.IO 确实在可能的情况下使用 WebSocket 进行传输,但它为每个数据包添加了额外的元数据。这就是为什么 WebSocket 客户端将无法成功连接到 Socket.IO 服务器,而 Socket.IO 客户端也将无法连接到普通 WebSocket 服务器。
-
快速开始
Server 端
下面的代码就能启动一个 socket.io server,客户端可以连接对应的 3000 端口
const express = require('express');
const app = express();
const http = require('http');
const server = http.createServer(app);
const { Server } = require("socket.io");
const io = new Server(server);
app.get('/', (req, res) => {
res.sendFile(__dirname + '/index.html');
});
io.on('connection', (socket) => {
console.log('a user connected');
});
server.listen(3000, () => {
console.log('listening on *:3000');
});
跨域支持
const io = new Server(httpServer, {
/* options */
cors: {
origin: "*",
},
});
Server 实例 connection 事件
当有新的 client 连上了时触发,事件回调函数的第一个参数是 socket 实例,后续使用这个 socket 实例和这个 client 进行通信。
目前都是使用单播的方式实现的,所以这个需要缓存,如果使用广播和组播的方案这个 socket 是不是就不用缓存了?
Client 端
引入
pnpm add socket.io-client
import io from "socket.io-client";
const socket = io("http://192.168.16.119:3001/");
socket.on("connect", () => {
console.log("socket.io connected");
console.log(socket.id);
console.log(socket.connected);
});
socket.on("disconnect", () => {
console.log("socket.io disconnect");
console.log(socket.connected);
});
socket.on("connect_error", (error) => {
console.log("socket.io error");
console.log(socket.connected);
});
客户端的 socket 实例和 Server 端的 socket 实例 id 一致,两个实例间通过 emit 接口发送消息,通过 on 接口订阅消息。
socket 连接相关的事件有 connect 、disconnect 和 connect_error。
Client 发送消息给 Server
Client 端代码:
const msg = { /* 消息内容 */ };
socket.emit("message", JSON.stringify(msg), (arg) => {
console.log(arg); // got it
});;
Server 端代码:
socket.on("message", (arg, callback) => {
const msg = JSON.parse(arg);
callback("got it");
});
上面的例子中,Client 端发送的内容在 Server 端 socket 实例 message 事件回调函数中获取,同时回调函数中 callback 的内容在 Client 发送的回调函数中能够获取到。
Server 发送消息给 Client
Server 端代码:
const stringifed = JSON.stringify(msgInfo);
this.list.forEach((it) => {
it.emit("message", stringifed);
});
Client 端代码:
socket.on("message", , (arg) => {
console.log(arg);
})
Server 端发消息时需要通知所有的 Client,目前的实现方式是将所有连接的 socket 实例缓存下来,需要发送的时候遍历进行单播,也可以使用广播和组播的方式进行实现。
超时异常检测
上面都是默认 emit 接口可以成功,异常检测的处理方法如下
socket.timeout(5000).emit("my-event", (err, response) => {
if (err) {
// the other side did not acknowledge the event in the given delay
} else {
console.log(response);
}
});