Websocket transport reliability (Socket.io data loss during reconnection)

前端 未结 8 2433
梦谈多话
梦谈多话 2020-12-02 04:58

Used

NodeJS, Socket.io

Problem

Imagine there are 2 users U1 & U2, connected to an app via Socket.io. The al

8条回答
  •  半阙折子戏
    2020-12-02 05:23

    What I think you want is to have a reusable socket for each user, something like:

    Client:

    socket.on("msg", function(){
        socket.send("msg-conf");
    });
    

    Server:

    // Add this socket property to all users, with your existing user system
    user.socket = {
        messages:[],
        io:null
    }
    user.send = function(msg){ // Call this method to send a message
        if(this.socket.io){ // this.io will be set to null when dissconnected
            // Wait For Confirmation that message was sent.
            var hasconf = false;
            this.socket.io.on("msg-conf", function(data){
                // Expect the client to emit "msg-conf"
                hasconf = true;
            });
            // send the message
            this.socket.io.send("msg", msg); // if connected, call socket.io's send method
            setTimeout(function(){
                if(!hasconf){
                    this.socket = null; // If the client did not respond, mark them as offline.
                    this.socket.messages.push(msg); // Add it to the queue
                }
            }, 60 * 1000); // Make sure this is the same as your timeout.
    
        } else {
            this.socket.messages.push(msg); // Otherwise, it's offline. Add it to the message queue
        }
    }
    user.flush = function(){ // Call this when user comes back online
        for(var msg in this.socket.messages){ // For every message in the queue, send it.
            this.send(msg);
        }
    }
    // Make Sure this runs whenever the user gets logged in/comes online
    user.onconnect = function(socket){
        this.socket.io = socket; // Set the socket.io socket
        this.flush(); // Send all messages that are waiting
    }
    // Make sure this is called when the user disconnects/logs out
    user.disconnect = function(){
        self.socket.io = null; // Set the socket to null, so any messages are queued not send.
    }
    

    Then the socket queue is preserved between disconnects.

    Make sure it saves each users socket property to the database and make the methods part of your user prototype. The database does not matter, just save it however you have been saving your users.

    This will avoid the problem mentioned in Additon 1 by requiring a confirmation from the client before marking the message as sent. If you really wanted to, you could give each message an id and have the client send the message id to msg-conf, then check it.

    In this example, user is the template user that all users are copied from, or like the user prototype.

    Note: This has not been tested.

提交回复
热议问题