43

I'm making a chat app with socket.io, and I'd like to use my custom client id, instead of the default ones (8411473621394412707, 1120516437992682114). Is there any ways of sending the custom identifier when connecting or just using something to track a custom name for each ID? Thanks!

pmerino
  • 5,900
  • 11
  • 57
  • 76
  • Best solution is here (client can its identity/ or name itself, and send it via socket.handshake.query on connection) https://stackoverflow.com/a/39711590/984471 – Manohar Reddy Poreddy Nov 24 '19 at 14:34

11 Answers11

55

You can create an array on the server, and store custom objects on it. For example, you could store the id created by Socket.io and a custom ID sent by each client to the server:

var util = require("util"),
    io = require('/socket.io').listen(8080),
    fs = require('fs'),
    os = require('os'),
    url = require('url');

    var clients =[];

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

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

            var clientInfo = new Object();
            clientInfo.customId         = data.customId;
            clientInfo.clientId     = socket.id;
            clients.push(clientInfo);
        });

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

            for( var i=0, len=clients.length; i<len; ++i ){
                var c = clients[i];

                if(c.clientId == socket.id){
                    clients.splice(i,1);
                    break;
                }
            }

        });
    });

in this example, you need to call storeClientInfo from each client.

<script>
    var socket = io.connect('http://localhost', {port: 8080});

    socket.on('connect', function (data) {
        socket.emit('storeClientInfo', { customId:"000CustomIdHere0000" });
    });
</script>

Hope this helps.

oscarm
  • 2,630
  • 6
  • 41
  • 74
  • Can we set CustomId from URL Query string parameter id from client side? – Vijaysinh Parmar Sep 21 '15 at 07:09
  • 1
    Do not change the socket IDs to ones of your own choosing, it breaks the Socket.io room system entirely. It will fail silently and you'll have no clue why your clients aren't receiving the messages. –  Apr 08 '16 at 06:26
  • 3
    I would recommend using Redis instead of the variable. It will offer better scalability and you won't lose your data if your server crashes due to errors. – Mohit Gangrade Aug 14 '16 at 07:33
  • The question is not about scalability. This is just a way to manage IDs. – oscarm Aug 17 '16 at 18:12
20

To set custom socket id, generateId function must be overwritten. Both of eio and engine props of Socket.io server object can be used for to manage this operation.

A simple example:

var app = require('express')();
var http = require('http').Server(app);
var io = require('socket.io')(http);

io.engine.generateId = function (req) {
    // generate a new custom id here
    return 1
}

io.on('connection', function (socket) {
    console.log(socket.id); // writes 1 on the console
})

It seems to be it has been handled.

It must be in mind that socket id must be unpredictable and unique value with considering security and the app operations!

Extra: If socket.id is returned as undefined because of your intense processes on your generateId method, async/await combination can be used to overcome this issue on node.js version 7.6.0 and later.
handshake method of node_modules/engine.io/lib/server.js file should be changed as following:

current:

// engine.io/lib/server.js

Server.prototype.generateId = function (req) {
  return base64id.generateId();
};

Server.prototype.handshake = function (transportName, req) {
  var id = this.generateId(req);
  ...
}

new:

// function assignment

io.engine.generateId = function (req) {
  return new Promise(function (resolve, reject) {
    let id;
    // some intense id generation processes
    // ...
    resolve(id);
  });
};


// engine.io/lib/server.js

Server.prototype.handshake = async function (transportName, req) {
  var id = await this.generateId(req);
  ...
}

Note: At Engine.io v4.0, generateId method would accept a callback. So it would not needed to change handshake method. Only generateId method replacement is going to be enough. For instance:

io.engine.generateId = function (req, callback) {
  // some intense id generation processes
  // ...
  callback(id);
};
efkan
  • 12,991
  • 6
  • 73
  • 106
  • 2
    Why is it important that this id is unpredictable? Can clients specify their own id on connecting? If not I dont see why this is necessary – user3916570 Oct 14 '17 at 03:08
  • Actually it depends on what you want. Q1-Answer: Predictable id might cause security issues. Q2-Answer: Yes, they can. But then server never know which client does what. – efkan Oct 14 '17 at 06:46
  • 1
    "It must be in mind that socket id must be unpredictable ... considering security ... might cause security issues ..." Can you give an example of a security issue? The socket.io and engine.io docs mention nothing about this AFAIK. Did you just make this up? – spinkus Feb 23 '20 at 03:47
  • Bro if I want to pass argument (value) from front-end then how to pass and access in here. please help. – Rohit Nishad Apr 01 '20 at 13:18
  • 1
    @spinkus I imagine it is because if you could predict someone's socketId you could trick the server into thinking you were that person and get access to all of their data. – Ryan Soderberg Apr 24 '20 at 22:49
  • 1
    @RohitNishad I implemented that. You need to send an object with a query as the second argument when connecting from the client, like this: `{ query: { foo: 'foo' } }`. Then on the server you have to grab that by parsing the req.url as described [here](https://nodejs.org/api/url.html#url_constructor_new_url_input_base), like this: `const parsedUrl = new url.URL(req.url, host)`. Once you have parsed the url you can access the query params like this: `parsedUrl.searchParams.get('foo')`. Drop a link if you have a stack overflow question and it'll be easier to explain it there – Daniel Reina Jun 13 '20 at 17:49
8

In the newest socket.io (version 1.x) you can do something like this

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

socket.on('connect', function() {
    console.log(socket.io.engine.id);     // old ID
    socket.io.engine.id = 'new ID';
    console.log(socket.io.engine.id);     // new ID
});
Salvador Dali
  • 214,103
  • 147
  • 703
  • 753
6

I would use an object as a hash lookup - this will save you looping through an array

var clients = {};
clients[customId] = clientId;

var lookup = clients[customId];
James Westgate
  • 11,306
  • 8
  • 61
  • 68
6

Do not change the socket IDs to ones of your own choosing, it breaks the Socket.io room system entirely. It will fail silently and you'll have no clue why your clients aren't receiving the messages.

6

This will work with 2.2.0 and above version of Socket.IO

To set custom Socket Id, generateId function must be overwritten.

A simple example:

Server Side

var app = require('express')();
var http = require('http').Server(app);
var io = require('socket.io')(http);

io.use((socket, next) => {
  io.engine.generateId = () => {
    // USE ONE OF THESE
    socket.handshake.query.CustomId; // this work for me
    // return socket.handshake.query.CustomId;
  }
  next(null, true);
});

io.on('connection', function (socket) {
    console.log(socket.id);
})

Clint Side

io.connect(URL, { query: "CustomId = CUSTOM ID IS HERE" })

NOTE: Keep in mind that socket id must be a unique value.

Rohit Nishad
  • 2,570
  • 2
  • 22
  • 32
5

why not a simpler solution that does not need to maintain an array of connected clients and does not override internal socket id?

io.on("connection", (socket) => {
    socket.on('storeClientInfo', (data) => {
        console.log("connected custom id:", data.customId);
        socket.customId = data.customId;
    });

    socket.on("disconnect", () => {
        console.log("disconnected custom id:", socket.customId);
    })
});

Client side

let customId = "your_custom_device_id";
socket.on("connect", () => {
    socket.emit('storeClientInfo', { customId: customId });
});
Marco Grassi
  • 51
  • 1
  • 3
4

or you can override the socket id, like this:

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

      socket.id = "YOUR_CUSTOM_ID";
});

you can see under the array:

io.sockets.sockets

Aviram Netanel
  • 12,633
  • 9
  • 45
  • 69
  • 1
    I suspect this is a better solution, especially when having to scale out with multiple processes – James Westgate Jun 10 '14 at 09:46
  • 1
    This works to change the id but the socket is still referenced by it's original id in cases like `io.sockets.connected[socketid]` – RossBille Apr 29 '15 at 03:41
  • 2
    Overwriting the existing socket.id causes problems for socket.io in maintaining its own data structures. This is NOT a good solution. Just use a different property name for a custom id. – jfriend00 Mar 24 '16 at 20:21
  • socket.id field is readonly now and can not be set with any value in socket.io v4 – cekeriya Apr 27 '22 at 10:07
2

Can store customId (example userId) in object format instead of for loop, this will improve performance during connection, disconnect and retrieving socketId for emitting

`

 var userId_SocketId_KeyPair = {};
 var socketId_UserId_KeyPair = {};

_io.on('connection', (socket) => {
    console.log('Client connected');
    //On socket disconnect
    socket.on('disconnect', () => {
        // Removing sockets
        let socketId = socket.id;
        let userId = socketId_UserId_KeyPair[socketId];
        delete socketId_UserId_KeyPair[socketId];
        if (userId != undefined) {
            delete userId_SocketId_KeyPair[userId];
        }
        console.log("onDisconnect deleted socket with userId :" + "\nUserId,socketId :" + userId + "," + socketId);
    });

    //Store client info
    socket.on('storeClientInfo', function (data) {
        let jsonObject = JSON.parse(data);
        let userId = jsonObject.userId;
        let socketId = socket.id;
        userId_SocketId_KeyPair[userId] = socketId;
        socketId_UserId_KeyPair[socketId] = userId;
        console.log("storeClientInfo called with :" + data + "\nUserId,socketId :" + userId + "," + socketId);
    });
`
partikles
  • 331
  • 3
  • 13
  • you should add some details to your solution to improve answer quality. (why and how) – hering Aug 03 '17 at 12:59
  • 1
    He mentioned that it improves performance, which it does over e.g. an array as you can access the elements by string value (the tradeoff being that you have roughly double the storage size). I was looking for a fast yet simple solution and found it here – beyondtdr Jan 01 '21 at 21:58
2

With this 2.2.0 version of Socket.IO, you can achieve this.

io.use((socket, next) => {
  io.engine.generateId = () => socket.handshake.query.token;
  next(null, true);
});
Rohit Nishad
  • 2,570
  • 2
  • 22
  • 32
0

If you are trying to use a custom id to in order to communicate with a specific client then you can do this

io.on('connection', function(socket){
    socket.id = "someId"
    io.sockets.connected["someId"] = io.sockets.connected[socket.id];

    // them emit to it by id like this
    io.sockets.connected["someId"].emit("some message", "message content")
});
Ahmadposten
  • 267
  • 3
  • 15