webSocketServer node.js how to differentiate clients

node.jsWebsocket

node.js Problem Overview


I am trying to use sockets with node.js, I succeded but I don't know how to differentiate clients in my code. The part concerning sockets is this:

var WebSocketServer = require('ws').Server, 
    wss = new WebSocketServer({port: 8080});
wss.on('connection', function(ws) {
    ws.on('message', function(message) {
        console.log('received: %s', message); 
        ws.send(message);
    });
    ws.send('something');
});

This code works fine with my client js.

But I would like to send a message to a particular user or all users having sockets open on my server.

In my case I send a message as a client and I receive a response but the others user show nothing.

I would like for example user1 sends a message to the server via webSocket and I send a notification to user2 who has his socket open.

node.js Solutions


Solution 1 - node.js

In nodejs you can directly modify the ws client and add custom attributes for each client separately. Also you have a global variable wss.clients that can be used anywhere. Please try the following code with at least two clients connected:

var WebSocketServer = require('ws').Server;
var wss = new WebSocketServer({
    server: httpsServer
});


wss.getUniqueID = function () {
    function s4() {
        return Math.floor((1 + Math.random()) * 0x10000).toString(16).substring(1);
    }
    return s4() + s4() + '-' + s4();
};

wss.on('connection', function connection(ws, req) {
    ws.id = wss.getUniqueID();

    wss.clients.forEach(function each(client) {
        console.log('Client.ID: ' + client.id);
    });
});

You can also pass parameters directly in the client connection URL:

https://myhost:8080?myCustomParam=1111&myCustomID=2222

In the connection function you can get these parameters and assign them directly to your ws client:

wss.on('connection', function connection(ws, req) {

    const parameters = url.parse(req.url, true);

    ws.uid = wss.getUniqueID();
    ws.chatRoom = {uid: parameters.query.myCustomID};
    ws.hereMyCustomParameter = parameters.query.myCustomParam;
}

Solution 2 - node.js

You can simply assign users ID to an array CLIENTS[], this will contain all users. You can directly send message to all users as given below:

var WebSocketServer = require('ws').Server,
    wss = new WebSocketServer({port: 8080}),
    CLIENTS=[];

wss.on('connection', function(ws) {
    CLIENTS.push(ws);
    ws.on('message', function(message) {
        console.log('received: %s', message);
        sendAll(message);
    });
    ws.send("NEW USER JOINED");
});

function sendAll (message) {
    for (var i=0; i<CLIENTS.length; i++) {
        CLIENTS[i].send("Message: " + message);
    }
}

Solution 3 - node.js

you can use request header 'sec-websocket-key'

wss.on('connection', (ws, req) => {
  ws.id = req.headers['sec-websocket-key']; 
  
  //statements...
});

Solution 4 - node.js

This code snippet in Worlize server really helped me a lot. Even though you're using ws, the code should be easily adaptable. I've selected the important parts here:

// initialization
var connections = {};
var connectionIDCounter = 0;

// when handling a new connection
connection.id = connectionIDCounter ++;
connections[connection.id] = connection;
// in your case you would rewrite these 2 lines as
ws.id = connectionIDCounter ++;
connections[ws.id] = ws;

// when a connection is closed
delete connections[connection.id];
// in your case you would rewrite this line as
delete connections[ws.id];

Now you can easily create a broadcast() and sendToConnectionId() function as shown in the linked code.

Hope that helps.

Solution 5 - node.js

It depends which websocket you are using. For example, the fastest one, found here: https://github.com/websockets/ws is able to do a broadcast via this method:

var WebSocketServer = require('ws').Server,
   wss = new WebSocketServer({host:'xxxx',port:xxxx}),
   users = [];
wss.broadcast = function broadcast(data) {
wss.clients.forEach(function each(client) {
  client.send(data);
 });
};

Then later in your code you can use wss.broadcast(message) to send to all. For sending a PM to an individual user I do the following:

(1) In my message that I send to the server I include a username (2) Then, in onMessage I save the websocket in the array with that username, then retrieve it by username later:

wss.on('connection', function(ws) {

  ws.on('message', function(message) {

      users[message.userName] = ws;

(3) To send to a particular user you can then do users[userName].send(message);

Solution 6 - node.js

I'm using fd from the ws object. It should be unique per client.

var clientID = ws._socket._handle.fd;

I get a different number when I open a new browser tab.

The first ws had 11, the next had 12.

Solution 7 - node.js

You can check the connection object. It has built-in identification for every connected client; you can find it here:

let id=ws._ultron.id;
console.log(id);

Solution 8 - node.js

One possible solution here could be appending the deviceId in front of the user id, so we get to separate multiple users with same user id but on different devices.

ws://xxxxxxx:9000/userID/<<deviceId>>

Solution 9 - node.js

By clients if you mean the open connections, then you can use ws.upgradeReq.headers['sec-websocket-key'] as the identifier. And keep all socket objects in an array.

But if you want to identify your user then you'll need to add user specific data to socket object.

Solution 10 - node.js

If someone here is maybe using koa-websocket library, server instance of WebSocket is attached to ctx along side the request. That makes it really easy to manipulate the wss.clients Set (set of sessions in ws). For example pass parameters through URL and add it to Websocket instance something like this:

const wss = ctx.app.ws.server
const { userId } = ctx.request.query

try{

   ctx.websocket.uid = userId
    
}catch(err){
    console.log(err)
}

Solution 11 - node.js

Use a global counter variable and assign its value for every new connection:

const wss = new WebSocket.Server({server});
let count_clients = 0;
wss.on('connection', function connection(ws){
	ws.id=count_clients++;
	console.log(`new connection, ws.id=${ws.id}, ${ws._socket.remoteAddress}:${ws._socket.remotePort} #clients=${wss.clients.size}`);
	ws.on('close', req => {console.log(`disconnected, ws.id=${ws.id}, ${ws._socket.remoteAddress}:${ws._socket.remotePort} #clients=${wss.clients.size}`);});
...

Solution 12 - node.js

Here is what I did:

* on connect, server generate an unique id (e.g uuid) for the connection,
    * save it in memory, (e.g as key of map),
    * send back to client in response,
    * 
* 
* client save the id, on each request with also send the id as part of request data,
* then server identify the client by id, on receive further request,
* 
* server maintain client, e.g cleanup on close/error,
* 

I've impl the idea, it works well to identify the client.
And, I also achieved group/topic broadcast based on the idea, which need the server to maintain extra info.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionAjouveView Question on Stackoverflow
Solution 1 - node.jsJzapataView Answer on Stackoverflow
Solution 2 - node.jsAnkit BishtView Answer on Stackoverflow
Solution 3 - node.jsSerhat AtesView Answer on Stackoverflow
Solution 4 - node.jsFirstVertexView Answer on Stackoverflow
Solution 5 - node.jsdroid-zillaView Answer on Stackoverflow
Solution 6 - node.jsKlaus HessellundView Answer on Stackoverflow
Solution 7 - node.jsrrkjonnapalliView Answer on Stackoverflow
Solution 8 - node.jscyberrspirittView Answer on Stackoverflow
Solution 9 - node.jsDeepak ChaudharyView Answer on Stackoverflow
Solution 10 - node.jsMarko BalažicView Answer on Stackoverflow
Solution 11 - node.jsMendi BarelView Answer on Stackoverflow
Solution 12 - node.jsEricView Answer on Stackoverflow