106

Can't handle this disconnect event, don't know why socket is not sent to the client / client doesn't respond!

Server

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

  socket.on('NewPlayer', function(data1) {

    online = online + 1;
    console.log('Online players : ' + online);
    console.log('New player connected : ' + data1);
    Players[data1] = data1;
    console.log(Players);

  });

  socket.on('DelPlayer', function(data) {

    delete Players[data];
    console.log(Players);
    console.log('Adios' + data);

  });

  socket.on('disconnect', function () {

      socket.emit('disconnected');
      online = online - 1;

  });

});

Client

 var socket = io.connect('http://localhost');

    socket.on('connect', function () { 

        person_name = prompt("Welcome. Please enter your name");

        socket.emit('NewPlayer', person_name);

        socket.on('disconnected', function() {

            socket.emit('DelPlayer', person_name);

        });

    });

As you can see when a client disconnects the Array object[person_name] should be deleted, but it's not.

Null
  • 1,950
  • 9
  • 30
  • 33
Raggaer
  • 3,244
  • 8
  • 36
  • 67
  • You better try other way around, first delete the player then disconnect. Because once you've disconnected from the server the server wont be able to receive the event which client emits. Keep track of the socket rather than the player, by which you can remove players easily. – code-jaff Jun 25 '13 at 11:20
  • How should I delete the player and then disconnect? how do I know when the player is gonna disconnect?. – Raggaer Jun 25 '13 at 11:29
  • 4
    shouldn't the event on the client be `'disconnect'` instead of `'disconnected'` ? – Sherlock Jan 06 '15 at 19:03
  • 1
    @Sherlock in OP's original client code they were attempting to listen to a custom event they were triggering serverside for disconnected logic. 'disconnect' is indeed the built in disconnect event, but it doesn't contribute directly to the issue they are experiencing. – Jon Church May 24 '18 at 12:40

4 Answers4

199

Ok, instead of identifying players by name track with sockets through which they have connected. You can have a implementation like

Server

var allClients = [];
io.sockets.on('connection', function(socket) {
   allClients.push(socket);

   socket.on('disconnect', function() {
      console.log('Got disconnect!');

      var i = allClients.indexOf(socket);
      allClients.splice(i, 1);
   });
});

Hope this will help you to think in another way

nick
  • 18,784
  • 2
  • 24
  • 31
code-jaff
  • 9,230
  • 4
  • 35
  • 56
  • 101
    Better use `allClients.splice(i, 1)` to delete an element. `delete allClients[i]` will just set the array position to `undefined` – Yves Nov 21 '13 at 15:47
  • 2
    Why it is working, but the tracking people with their names solution is not working? – sha1 Jun 10 '14 at 19:11
  • This is not working for me. Here `i` got a value of -1 every time. Can you tell me what is going on. – Vinit Chouhan Feb 17 '15 at 22:44
  • 1
    @VinitChouhan you should probably ask separate question with your actual issue. – code-jaff Feb 18 '15 at 03:52
  • When you get a value of -1, it means you're trying to splice a socket that does not exist (someone disconnects but you have not registered the person yet in your `allClients` array). I suggest you just return: `if (i === -1)return;` before trying to splice it. – Koeno Jun 13 '16 at 14:21
  • @Slence As a safety measure it's okay, but it's almost impossible for a socket to emit a `disconnect` event which is not connected (where the actual socket registration happens). – code-jaff Jun 14 '16 at 03:58
  • What if there are multiple clients with the same name? –  Oct 06 '16 at 09:45
  • What Yves stated, use splice rather than delete. Ran into this problem several times over. – simon Jun 01 '17 at 21:18
29

For those wondering why the OP's code doesn't work -

OP's logic for deleting player at server side is in the handler for DelPlayer event, and the code that emits this event (DelPlayer) is in inside disconnected event callback of client.

The server side code that emits this disconnected event is inside the disconnect event callback which is fired when the socket loses connection. Since the socket already lost connection, disconnected event doesn't reach the client.


Accepted solution executes the logic on disconnect event at server side, which is fired when the socket disconnects, hence works.

T J
  • 42,762
  • 13
  • 83
  • 138
10

Create a Map or a Set, and using "on connection" event set to it each connected socket, in reverse "once disconnect" event delete that socket from the Map we created earlier

import * as Server from 'socket.io';

const io = Server();
io.listen(3000);

const connections = new Set();

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

  connections.add(s);

  s.once('disconnect', function () {
    connections.delete(s);
  });

});
Alexander Mills
  • 90,741
  • 139
  • 482
  • 817
1

You can also, if you like use socket id to manage your player list like this.

io.on('connection', function(socket){
  socket.on('disconnect', function() {
    console.log("disconnect")
    for(var i = 0; i < onlineplayers.length; i++ ){
      if(onlineplayers[i].socket === socket.id){
        console.log(onlineplayers[i].code + " just disconnected")
        onlineplayers.splice(i, 1)
      }
    }
    io.emit('players', onlineplayers)
  })

  socket.on('lobby_join', function(player) {
    if(player.available === false) return
    var exists = false
    for(var i = 0; i < onlineplayers.length; i++ ){
      if(onlineplayers[i].code === player.code){
        exists = true
      }
    }
    if(exists === false){
      onlineplayers.push({
        code: player.code,
        socket:socket.id
      })
    }
    io.emit('players', onlineplayers)
  })

  socket.on('lobby_leave', function(player) {
    var exists = false
    for(var i = 0; i < onlineplayers.length; i++ ){
      if(onlineplayers[i].code === player.code){
        onlineplayers.splice(i, 1)
      }
    }
    io.emit('players', onlineplayers)
  })
})
www-data
  • 244
  • 2
  • 9