36

We can trace if a connection is established or disconnected by this code

console.log('a user connected');
    socket.on('disconnect', function () {
        console.log('user disconnected');
    });

Well, its fine. But how can we determine what user connected or gone offline. My client is written in PHP/HTML so they have a user ID.

Shahid Karimi
  • 4,096
  • 17
  • 62
  • 104
  • I'm not sure to get your question. Do you want a way for the client to check if other clients are online or not ? Or do you want a way for the server to determine what are the connected clients ? – Maxime Piraux Aug 21 '15 at 11:12

3 Answers3

64

If your clients have specific user IDs they need to send them to socket.io server. E.g. on client side you can do

// Browser (front-end)
<script>
 const socket = io();
 socket.emit('login',{userId:'YourUserID'});
</script>

And on server you will put something like

// server (back-end)
const users = {};
io.on('connection', function(socket){
  console.log('a user connected');

  socket.on('login', function(data){
    console.log('a user ' + data.userId + ' connected');
    // saving userId to object with socket ID
    users[socket.id] = data.userId;
  });

  socket.on('disconnect', function(){
    console.log('user ' + users[socket.id] + ' disconnected');
    // remove saved socket from users object
    delete users[socket.id];
  });
});

Now you can pair socket ID to your user ID and work with it.

galethil
  • 996
  • 8
  • 13
  • 2
    Shouldn't you be deleting the user from the users array when they disconnect? – Kilizo Dec 22 '16 at 12:29
  • Well, it depends on functionality. Since it is a custom userID you might want to remember the history of logged in users. But this is not the point of this question. – galethil Dec 22 '16 at 13:27
  • 5
    however, socket id change whenever client browser refreshes. so my question is do you need to add every socket id whenever it change in order to maintain online status? – Shift 'n Tab Apr 19 '18 at 05:56
  • 3
    This is a good question. If you just remove the socket.id key from users object on disconnect event, user will create new socket.id when reconnecting to server and save his userId there. – galethil Apr 19 '18 at 13:09
  • 1
    Okay, I have additional question for this. If I want to remove the socket entry of user in array everytime its been desconnected, then how to do it in code? – Jesus Erwin Suarez Nov 13 '19 at 01:08
  • 1
    @JesusErwinSuarez I've added the removing socket from users object. – galethil Nov 25 '19 at 12:38
  • 2
    @galethil When i open more than 1 tab, so every new tab will create new socket id for same user, i think you need to manage array of socket ids for particular user. – turivishal Dec 05 '20 at 07:57
  • @galethil On every msg, the socket id changes so this approach wouldn't work. – AlxVallejo May 05 '23 at 16:24
15

In addition of @galethil's answer, What if user opens more than one tab (socket connection), each tab (socket connection) has unique socket id for single user, so we need to manage array of socket ids for particular user,

Client Side Connection: Support Socket IO Client v3.x,

<!-- SOCKET LIBRARY IN HTML -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/3.0.5/socket.io.js"></script>
const host = "http://yourdomain.com";
// PASS your query parameters
const queryParams = { userId: 123 };
const socket = io(host, {
    path: "/pathToConnection",
    transports: ['websocket'],  // https://stackoverflow.com/a/52180905/8987128
    upgrade: false,
    query: queryParams,
    reconnection: false,
    rejectUnauthorized: false
});

socket.once("connect", () => {
    
    // USER IS ONLINE
    socket.on("online", (userId) => {
        console.log(userId, "Is Online!"); // update online status
    });

    // USER IS OFFLINE
    socket.on("offline", (userId) => {
        console.log(userId, "Is Offline!"); // update offline status
    });

});

Server Side Connection: Support Socket IO Server v3.x,

  • Dependencies:
const _ = require("lodash");
const express = require('express');
const app = express();
const port = 3000; // define your port
const server = app.listen(port, () => {
  console.log(`We are Listening on port ${port}...`);
});
  • Connection:
const io = require('socket.io')(server, {
    path: "/pathToConnection"
});
let users = {};
io.on('connection', (socket) => {

  let userId = socket.handshake.query.userId; // GET USER ID
  
  // CHECK IS USER EXHIST 
  if (!users[userId]) users[userId] = [];
  
  // PUSH SOCKET ID FOR PARTICULAR USER ID
  users[userId].push(socket.id);
   
  // USER IS ONLINE BROAD CAST TO ALL CONNECTED USERS
  io.sockets.emit("online", userId);

  // DISCONNECT EVENT
  socket.on('disconnect', (reason) => {

    // REMOVE FROM SOCKET USERS
    _.remove(users[userId], (u) => u === socket.id);
    if (users[userId].length === 0) {
      // ISER IS OFFLINE BROAD CAST TO ALL CONNECTED USERS
      io.sockets.emit("offline", userId);
      // REMOVE OBJECT
      delete users[userId];
    }
   
    socket.disconnect(); // DISCONNECT SOCKET

  });

});

GitHub Demo

turivishal
  • 34,368
  • 7
  • 36
  • 59
  • Hi, I tested what you said, and it doesn't seem like opening a new tab creates a new socket id. Maybe socket.io has changed something recently? – isaacsan 123 Apr 15 '21 at 13:21
  • i have tested it till version 3 its working, i am not sure for above version, what version you are using? – turivishal Apr 15 '21 at 13:46
  • Ah, yeah, I'm using version 4.0.1. Didn't realize. I thought we were still at version 3 haha. Anyway, looks like that isn't the case for version 4. Id stays consistent now. – isaacsan 123 Apr 15 '21 at 16:25
  • i have tested in version 4.0.1 its same functionality as version 3.0, i think you are doing something wrong. you can follow the attached github demo, just update socket.io npm to latest and update latest version in index.html file. – turivishal Apr 15 '21 at 18:31
  • 1
    Hi, you're right. I made a mistake. I appreciate the help! – isaacsan 123 Apr 25 '21 at 09:16
3

We can identify the socket id in server who is connected and who is disconnected. So you can do something like this. You can use this setup if you have an identifier in client side

CLIENT

socket.emit('login', userId);

SERVER SIDE

const users = {};
io.on("connection", (socket) => {

   socket.on("login", (data) => {
      users[socket.id] = data;
    });

  socket.on("disconnecting", (reason) => {
    
    delete users[socket.id]; // remove the user. -- maybe not the exact code
  });
});

Hope you get the idea.

MBK
  • 2,589
  • 21
  • 25