私信 - 第三部分
本指南分为四个不同的部分
这是我们在 第二部分 结束时的位置
一切运行良好,但有一个非常烦人的问题
- 当发送者断开连接时,它发送的所有数据包都会 缓冲 直到重新连接(在这种情况下很棒)
- 但当接收者断开连接时,数据包会丢失,因为在给定房间中没有监听的 Socket 实例
这个问题有多种解决方案,我们将选择最容易实现的解决方案:将所有消息存储在服务器端。
注意:这第三部分将很简短,但它强调了 Socket.IO 的一个重要特性:你不能依赖连接的状态。它应该大部分时间都处于连接状态,但有无数的事情会导致 TCP 连接断开(这在移动浏览器上尤其如此)。
安装
让我们检出第三部分的分支
git checkout examples/private-messaging-part-3
以下是您在当前目录中应该看到的内容
├── babel.config.js
├── package.json
├── public
│ ├── favicon.ico
│ ├── fonts
│ │ └── Lato-Regular.ttf
│ └── index.html
├── README.md
├── server
│ ├── index.js (updated)
│ ├── messageStore.js (created)
│ ├── package.json
│ └── sessionStore.js
└── src
├── App.vue
├── components
│ ├── Chat.vue (updated)
│ ├── MessagePanel.vue
│ ├── SelectUsername.vue
│ ├── StatusIcon.vue
│ └── User.vue
├── main.js
└── socket.js
完整的差异可以在 这里 找到。
工作原理
持久消息
在服务器端 (server/index.js
),我们现在将消息持久化到我们的新存储中
io.on("connection", (socket) => {
// ...
socket.on("private message", ({ content, to }) => {
const message = {
content,
from: socket.userID,
to,
};
socket.to(to).to(socket.userID).emit("private message", message);
messageStore.saveMessage(message);
});
// ...
});
我们在连接时获取消息列表
io.on("connection", (socket) => {
// ...
const users = [];
const messagesPerUser = new Map();
messageStore.findMessagesForUser(socket.userID).forEach((message) => {
const { from, to } = message;
const otherUser = socket.userID === from ? to : from;
if (messagesPerUser.has(otherUser)) {
messagesPerUser.get(otherUser).push(message);
} else {
messagesPerUser.set(otherUser, [message]);
}
});
sessionStore.findAllSessions().forEach((session) => {
users.push({
userID: session.userID,
username: session.username,
connected: session.connected,
messages: messagesPerUser.get(session.userID) || [],
});
});
socket.emit("users", users);
// ...
});
代码非常简单。我们不应该再在断开连接时丢失消息了
回顾
现在我们有了功能完备的聊天,我们将在本指南的 第四部分 中了解如何扩展到多个 Socket.IO 服务器。
感谢您的阅读!