跳至主要內容

私人訊息傳遞 - 第三部分

本指南分為四個不同的部分

以下是我們在第二部分結束時的情況

Chat (v2)

一切都運作得很好,但有一個最後的問題很令人困擾

  • 當發送者斷線時,它所傳送的所有封包都會緩衝,直到重新連線(在這種情況下很好)
Chat with sender that gets disconnected
  • 但是當接收者斷線時,封包就會遺失,因為在指定的房間中沒有 Socket 執行個體在監聽
Chat with recipient that gets disconnected

這個問題有多種解決方案,我們將採用最容易實作的方法:將所有訊息儲存在伺服器端。

注意:第三部分會很簡短,但它強調了 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

完整的 diff 可以在此找到。

運作方式

持續訊息

在伺服器端 (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);
// ...
});

該程式碼相當簡單。我們不應該再在中斷連線時遺失訊息

Chat (v3)

檢閱

現在我們有了功能性的聊天室,我們將在這個指南的第 4 部分中了解如何擴充至多個 Socket.IO 伺服器。

感謝您的閱讀!