[英]How do I let socket.io server re-emit message to a particular socket when that socket re-connect?
我的服務器代碼使用io.to(socketId).emit('xxx');
要向特定套接字發送消息,請參閱https://socket.io/docs/emit-cheatsheet/
但是當連接壞了,客戶端斷開連接再次連接時,socketId發生變化, io.to(socketId).emit('xxx');
然后失敗。 那么如何實現重新發送方法來處理重新連接?
我的問題與這個問題相反, socket.io 在 x 秒/第一次嘗試獲得響應失敗后停止重新發出事件,從中我了解到 socket.io客戶端可以在重新連接時重新發出。 但是服務器代碼似乎缺乏這種支持。
- - 更新 - -
正如評論所說,我在這里顯示“您保存過時的 socketId 值的代碼上下文”。
首先,每個用戶在我們的系統中都有一個唯一的 id,當 socket 連接時,客戶端會發送一個登錄消息,所以我保存了 userId 和 socketId 對。 當我收到斷開連接事件時,我會清除該信息。
其次,用戶將通過 redis pubsub(來自其他服務)獲取消息,我將通過我記錄的 socketid 將該消息發送給客戶端。 因此,當套接字連接時,我將訂閱由 userid 標識的頻道並在斷開連接事件中取消訂閱。
第三,當我收到 redis pub 事件而 socketId 值變得陳舊時,就會發生我的問題。 實際上socketid的值是最新的,但是socket可能發送消息失敗。
io.on('connection', async function (socket) {
socket.on('login', async function (user_id, fn) {
...
await redis
.multi()
.hset('websocket:socket_user', socket.id, user_id)
.hset(
`websocket:${user_id}`,
'socketid',
socket.id
)
.exec()
await sub.subscribe(user_id)
...
}
socket.on('disconnect', async function (reason) {
let user_id = await redis.hget('websocket:socket_user', socket.id)
await redis.del(`websocket:${user_id}`)
sub.unsubscribe(user_id)
...
}
//Here is what problem happens when socket is trying to reconnect
//while I got redis pub message
sub.on('message', async function (channel, message) {
let socketid = await redis.hget(`websocket:${channel}`, 'socketid')
if (!socketid) {
return
}
//so now I assume the socketid is valid,
//but it turns out clients still complain they didn't receive message
io.to(socketid).emit('msg', message) //When it fails how do I re-emit?
})
我找不到任何現有的解決方案,所以這就是我想出的:
如何記錄失敗的消息是我發現 socket.io 不支持的另一項任務,這就是我所做的,
io.to(socketId).emit('xxx');
因為“從命名空間發出時不支持確認。” 所以我需要首先使用io.sockets.connected[socketid]
從 id 獲取套接字 object記錄失敗的代碼有點像這樣
let socket = io.sockets.connected[socketid]
if (!socket) return
let list_key = `websocket:${socketid}`
await redis.sadd(list_key, message)
socket.emit('msg', message, async (ack) => {
await redis.srem(list_key, message)
})
如果有人能提出更好的解決方案,我會全力以赴。 謝謝。
您可以通過覆蓋默認方法來為您的套接字客戶端生成自定義 socket.id 以生成套接字 id。 在這種情況下,socket.id 將為您所知,並且可以在相同的 id 上線時重新發出。
//使用節點請求 object (http.IncomingMessage) 作為第一個參數調用 function。 根據 socket.io 文檔
io.engine.generateId = (req) => {
return "custom:id:" + user_unique_id; // custom id must be unique
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.