socket.io assigning custom socket.id

24,196

Solution 1

socket.id is used internally by socket.io for its own socket list. You cannot overwrite that or you break some of its ability to maintain its own data structures.

You have two choices:

  1. You can use the existing socket.id value as is (without overwriting it) so you don't break existing behavior. It is already guaranteed to be unique on the server.
  2. You can use a different property name for your own id such as socket.userId and then you won't conflict.

If you need to, you can maintain a map between your own custom id and the socket.io socket.id so you could get to one from the other.

Similar question here: Socket.io custom client ID

Solution 2

generateId prop of io.engine object can be used for to set the custom id.

Using this way, the all socket ids can be created on the server side without any issue.

Actually I wrote an answer for a similar question today.

An 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) {

    // listing the default namespace rooms
    console.log("rooms: ", io.nsps["/"].adapter.rooms);

})

The console output would be as the following:
rooms: { '/#1': Room { sockets: { '/#1': true }, length: 1 } }

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:

former:

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

new:

Server.prototype.handshake = async function (transportName, req) {
  var id = await this.generateId(req);
  ...
}
Share:
24,196
LckySnday
Author by

LckySnday

Nothing special, just someone who want to learn something.

Updated on July 09, 2022

Comments

  • LckySnday
    LckySnday almost 2 years

    I keep track the list of every users connected in the array. So if there is a new connection, it will check whether the user is already on the list or not, if he was already on the list, then assign their socket.id with the corresponding socket.id on the list, otherwise just add them to the list.

    It's for preventing same user counted as 2 user while he attempt to do multi-login.

    Object.keys(client).forEach(function (key) {
        if (client[key].id == data.id){
            is_connected = true;
            socket.id = key;
        }
    });
    

    I have no problem handling the messages/chat that was sent/received by the user who attempt multi-login.

    socket.on('chat', function(msg){
        var data = {"name": client[socket.id].name, "message": msg};
        io.emit('chat', data);
    });
    

    The io.emit for the chat message was succesfully sent to the user who attempting multi-login.

    The problem I got was whenever the user decide to logout/disconnect from the server.

    io.emit('user_leave', client[socket.id].id);
    

    [Multi-Login Case] -> Multi-User and Dual-User are same user attempting Multi-Login

    Whenever the Main-User disconnected from the server, the Dual-User received 'user_leave' sent by the server, because io.emit supposed to send it to all sockets.

    But not otherwise, while the Sub-User disconnected from the server, the Main-user do not receive 'user_leave' emitted by the server.

    *Note: Main-User is login first, then the Dual-User. So the Main-User information was saved directly in the array, while the Sub-User socket.id was assigned with the Main-User socket.id

    [Update]

    Explanation

    B2 socket.id was assigned with B1 socket.id, the io.emit for chat work perfectly while io.emit for disconnect only emitted to All except Dual-User(B2)

    • efkan
      efkan about 7 years
      If you need to complete this operation you might setting generateId prop of io.eio or io.engine object. I've tried to explain over here stackoverflow.com/a/42483423/3765109
  • LckySnday
    LckySnday about 8 years
    Thanks for the answer, I do know overwriting socket.id may break some functionality, But if there is simple trick to fix my issue, then I will definitely go for it instead of re-design all the code.
  • user969068
    user969068 almost 7 years
    how can we include custom id from socket-client io.engine.generateId ? when we make connection from client io.connect('ws://IP:PORT'); ?
  • efkan
    efkan almost 7 years
    Setting a function to io.engine.generateId should be worked. Client is not important in this case and if I'm right 'ws' or 'https' is also not a subject. I guess you can manage it.
  • user969068
    user969068 almost 7 years
    what I am trying to do is from client side when I make a connection it send a custom client id to make connection, there is no way to call io.engine.generateId from client side, I think I have to pass as query like io.connect('ws://IP:PORT' {query: 'id=custom_id'}); , still trying to figure how can I assign that custom_id as socket.id on server before connection is established
  • efkan
    efkan almost 7 years
    I'm sorry for my misunderstanding. You've been trying to give a client socket id value on client side. Unfortunately my answer doesn't provide that. Socket Id is given by Socket Server in Socket Server. Why you have to give an id in client side? Generally this operation is needed in server side to give a socket id from a current database (like user id).