SocketIO Identify what user disconnected

11,131

Solution 1

You could just store the id value in the parent scope, which the disconnect event handler would have access to:

io.on('connection', function(socket) {
  var userId;
  socket.on('new player', function(id, name) {
    userId = id = parseInt(id);
    // ...
  });

  socket.on('disconnect', function() {
    delete playerList[userId];
  });
};

Solution 2

Maybe I'm late to the party but I was stuck with something similar and found it the hard way and this may help someone.

The best way to detect if the user is disconnected is would be to first set the username in socket session.

Send the name from the client on emit

socket.emit("newUser", username);

and on server

socket.on('newUser',function (username) {
     // we store the username in the socket session for this client
     socket.username = username;
});

and when the user disconnects find that on the disconnect event

socket.on('disconnect', function () {
    var connectionMessage = socket.username + " Disconnected from Socket " + socket.id;
    console.log(connectionMessage);
  });

and you can take it from there.

Solution 3

This worked for me:

On every new connection or user who comes online generate a socket Id, add it to the user object, and add it to the array of all the users online.

const users = [];
io.on('connection', (socket) => {
const socketId = socket.id; 


socket.on('user online', (data) => {

    users.push({ ...data, socketId });
    io.emit('view user online', user);
  });

Then in the disconnect, use forEach to loop through each object in the array, then use for to loop through and delete each key in the object:

 socket.on('disconnect', () => {
    users.forEach((user) => {
      if (user.socketId === socket.id) {
        for (const key in user) {
          delete user[key];
        }
      }
        });

        logger(`A user has disconnected`);
      });
      });
});

Tweak to the way you want.

Share:
11,131
Weastie
Author by

Weastie

Updated on June 14, 2022

Comments

  • Weastie
    Weastie almost 2 years

    I am making a simple Node.js game that uses Express, Socket.io, and an Http server. All of the users are stored in a multidimensional object on the server. This is how the server-side code works:

    var express = require('express');
    var app = express();
    var http = require('http').Server(app);
    var io = require('socket.io')(http);
    app.use(express.static(__dirname + '/'));
    
    var playerList = {};
    
    createPlayer = function(array,width,height,spdx,spdy,x,y,color,name,id) {
      var player = {
        width:width,
        height:height,
        spdx:spdx,
        spdy:spdy,
        x:x,
        y:y,
        wKeyDown:false,
        aKeyDown:false,
        sKeyDown:false,
        dKeyDown:false,
        color:color,
        name:name,
        id:id
      }
      array[id] = player;
    }
    
    io.on('connection', function(socket) {
      socket.on('new player', function(id, name) {
        id = parseInt(id);
        if (!playerList[id]) {
          createPlayer(playerList,25,25,4,4,Math.round(Math.random() * 800),Math.round(Math.random() * 600),randomColor(),name,id);
        }
    
        socket.on('pressW', function(id, keyDown) {
          playerList[id].wKeyDown = keyDown;
        });
        socket.on('pressA', function(id, keyDown) {
          playerList[id].aKeyDown = keyDown;
        });
        socket.on('pressS', function(id, keyDown) {
          playerList[id].sKeyDown = keyDown;
        });
        socket.on('pressD', function(id, keyDown) {
          playerList[id].dKeyDown = keyDown;
        });
      });
    
      socket.on('disconnect', function() {
    
      });
    };
    
    sendPlayerList = function() {
      //newPlayerList is used to prevent client from seeing other users IDs
      var newPlayerList = {};
      var count = 0;
      for (var q in playerList) {
        player = {
          x:playerList[q].x,
          y:playerList[q].y,
          width:playerList[q].width,
          height:playerList[q].height,
          color:playerList[q].color,
          name:playerList[q].name,
        }
        newPlayerList[count] = player;
        count++;
      }
    
      io.emit('edit playerlist', newPlayerList);
    }
    
    SPLInterval = setInterval(sendPlayerList, 1000);
    

    Here is the client-side code for connection:

    var id;
    $('#playbutton').click(function() {
      var name = document.getElementById('name').value;
      id = Math.floor(Date.now() * Math.random());
      socket.emit('new player', id, name);
    });
    

    On the client-side, in the update loop, when the game wants to tell the server your input, it emits your input like so:

    update = function() {
        ctx.clearRect(0,0,canvas.width,canvas.height);
        if (document.hasFocus()) {
          socket.emit('pressD', id, dKeyDown);
          socket.emit('pressS', id, sKeyDown);
          socket.emit('pressA', id, aKeyDown);
          socket.emit('pressW', id, wKeyDown);
        }else{
          socket.emit('pressD', id, false);
          socket.emit('pressS', id, false);
          socket.emit('pressA', id, false);
          socket.emit('pressW', id, false);
        }
        clientUpdatePlayer();
        updatePlayers();
      }
    }
    
    var updateInterval = setInterval(update, 31.25);
    

    The function to update players just draws players based on the player list sent from the server.

    My problem is that when a user disconnects, they stay in the player list. I don't understand how I should go about fixing this. I identify users by getting the ID they send from the client, but I can't get the user's id when they disconnect.

    There is a lot more code, but I tried to only include the code that I thought was necessary. I am willing to include more code if that is needed.

  • Weastie
    Weastie almost 9 years
    Would that work for multiple users? Wouldn't that just change the userId variable to the most recent player who connected?
  • mscdex
    mscdex almost 9 years
    Yes it would work for multiple users. You already have the correct scope from the connection event handler, so it's the same socket and thus the same user. So unless you have it such that a user can register multiple player names concurrently on the same socket, you should be ok.
  • Mehdi Akbarian Rastaghi
    Mehdi Akbarian Rastaghi over 7 years
    why its the correct answer?user A with id=1 connect to server and userId is 1 now after that userB with id=2 connect to server after userA and userId is 2!now if userA disconnect this callback will delete userB from playerList!!
  • Vikneshwar
    Vikneshwar about 6 years
    I think userId will have the id of the user who joined recently.
  • Farbod Ahmadian
    Farbod Ahmadian almost 4 years
    Please provide more information for further detail.
  • Anand Kumar Pandey
    Anand Kumar Pandey almost 4 years
    Find the user which has disconnected using "socket.id" const presentUser = users.find(user => user.id == socket.id); Then remove this user from the list of online users using, users = users.filter(user => user != presentUser);
  • Anand Kumar Pandey
    Anand Kumar Pandey almost 4 years
    Hope you are OK with the "arrow function" and the "find" and "filter" array methods in javascript.
  • Anand Kumar Pandey
    Anand Kumar Pandey almost 4 years
    const presentUser = users.find(user => user.id == socket.id); Here socket.id refers to the socket or client which triggered the disconnect event or the client which has disconnected.
  • Drkawashima
    Drkawashima over 2 years
    Upvoted! Even if the answer posted by mscdex would work, I think it feels much more reliable and flexible to store the username on the socket-object and be able to get it from there at all times.