0
votes

So I'm writing an app in NodeJS, and to preface my question please understand how my setup currently works:

I have Clients who connect via Socket.io to "Server X", and then my "Server X" connects via Socket.io to "Server Y", and they all send data back to each other via Socket.io.

Client <---> Server X <---> Server Y

Clients refer to users and their browsers, and then I have a node app running on both my server x and my server y.

So in the code below on my Server X, if you look at line 4 it works exactly as it should. It emits the message ONLY to the client who requested it.

io.on('connection', function(socket){

    // This works just fine.
    socket.emit('return_login', 'Test Message');

    socket.on('login', function(data){
        // This line correctly sends the data to Server Y
        server_y.emit('login', data);
    });

    server_y.on('return_login', function(data){
        // This emits to all connected clients???
        socket.emit('return_login', data);
    });

});

Now my problem is when "Server Y" emits return_login to server x, what I want to happen is for server x to take the value emitted by server y and just send it back to the original client, or web browser. But for some reason that line emits to ALL connected clients.

I have a laptop, this computer and my phone all testing this and every time that emit happens it sends to EVERYONE.

If someone could please help me with this I would greatly appreciate it. If I need to post more code please let me know.

2

2 Answers

1
votes

I am not sure about your code. But I usually use room to emit to an user and callback function of socket. This is my solution using callback instead of return_login event

io.on('connection', function(socket){
    socket.on('login', function(data, callback){
        
        // Using callback instead of return_login event
        server_y.emit('login', data, function(responseData){
          
          // put this socket to room as name = user_id
          socket.join(responseData.user_id);
          
          // return result by callback
          callback(responseData)
        });
    });

});

// emit to exactly user_id with return_login event if you want
io.to(user_id).emit('return_login', {key: 'ok'})
0
votes

It is sending to all clients because you have installed a separate listener for each socket for the return_login message. So, when one client logs in and the return_login message is sent back to your server, you have a separate listener for every single socket that sees that message and forwards it to that socket. In this way, it gets sent to every connected socket.

One way to fix that is to make sure that the return_login message is only sent to the socket that it belongs to. If you can send a socket.id with that message and have that server echo that id back as part of the response, then you can check that when you receive the message to make sure you only send it to the socket that it belongs to.

This is one of the issues with a pure message-based system. You are trying to do a request/response where only the requester sees the response, but socket.io isn't a request/response system. A response is sent to all listeners of that particular message and since you have a listener for that message for every single socket that is connected, every single socket is seeing it and then forwarding it on to it's client.

So, with a corresponding modification to the other server to echo back the id value, you could do this:

io.on('connection', function(socket){

    // This works just fine.
    socket.emit('return_login', 'Test Message');

    socket.on('login', function(data){
        // add our id so we can identify our response back
        data.id = socket.id;
        server_y.emit('login', data);
    });

    let fn = function(data) {
        // check to see if this message is destined for this socket
        if (data.id === socket.id) {
            // make data copy with id value removed so 
            //   we don't send that to the client
            let tempData = Object.assign({}, data);
            tempData.delete(id);
            socket.emit('return_login', tempData);
            // we're done with this listener so remove it
            server_y.removeListener('return_login', fn);
        }
    });

    server_y.on('return_login', fn);

});

It might be tempting to just remove your listener for the return_login message after you receive it, but that causes a race condition if two clients happen to both be in the process of logging in at the same time and thus both have listeners at the same time, then the first message would be received by both listeners.