Sending Message to a Specific Connected Users Using Websocket

Sending message to a specific connected users using webSocket?

This is not only the right way to go, but the only way. Basically each connection needs a unique ID. Otherwise you won't be able to identify them, it's as simple as that.

Now how you will represent it it's a different thing. Making an object with id and connection properties is a good way to do that ( I would definitely go for it ). You could also attach the id directly to connection object.

Also remember that if you want communication between users, then you have to send target user's ID as well, i.e. when user A wants to send a message to user B, then obviously A has to know the ID of B.

How to send message between users with same token using websocket?

I was not able to reproduce the issue as described, but was only able to receive the sent message to only one of the connected clients with the same token.

The issue with the single connected client is due to webSockets[userToken] = ws being referenced, as opposed to using an array of clients webSockets[userToken] = []; and webSockets[userToken].push(ws);

Also be sure that you do not have a zombie process of node server.js running in the background.

//...

const clients = {};

wss.on('connection', function connection(ws, req) {
let id = req.url.substring(req.url.lastIndexOf('/') + 1);
if ('' === id) {
//connecting id is missing
ws.terminate();

return;
}
if ('undefined' === typeof clients[id]) {
clients[id] = [];
}
console.log('Connection Received from IP: ' + req.socket.remoteAddress + ' with id ' + id);

//append websocket client to list of clients
clients[id].push(ws);

ws.on('message', function incoming(message) {
if ('' === message) {
//skip if message is blank
return;
}

try {
//process message as JSON object as "{"message": "string", "token": "string"}"
message = JSON.parse(message);
} catch(e) {
return;
}

if (!message.hasOwnProperty('token') || '' === message.token) {
//token was not sent or is empty
return;
}
let token = message.token;
console.log('Message received for token ' + token);

if ('undefined' !== typeof clients[token] && clients[token]) {
clients[token].forEach(function(client) {
if (client !== ws && client.readyState === WebSocket.OPEN) {
//do not send message back to the sending client
client.send(message.message + ' ' + token);
}
});
}

//inform sending client message was sent
ws.send('Sent: ' + message.message);
});

ws.on('close', function() {
clients[id].forEach(function(client, index) {
if (client === ws) {
//remove the client from the pool
clients[id].splice(index, 1);
}
});
});
});

html code

<button type="button" id="sendBtn" class="btn-primary">Send</button>

<script type="text/javascript">
const socket = new WebSocket('ws://localhost:8080/{{ token }}');
socket.onmessage = function(evt) {
window.console.log(evt.data);
};

jQuery(function($) {
$('#sendBtn').on('click', function() {
const message = {
"message": "Hello World",
"token": "{{ token }}"
};
socket.send(JSON.stringify(message));
});
});
</script>

websocket send to specific user nodejs

OK. Still trying to understand the actual spec you're shooting for. But, assuming the following (based on your answers to my prior questions):

  1. A client connects using a webSocket.
  2. When they send a message over that webSocket, that message is an id of something that can be looked up in your database and that they want regular updates for.
  3. Those updates for that particular id should be sent only to that specific client that requested it.
  4. If a different client connects and specifies some id, they should get updates for that id only.
  5. When a client sends a new message that specifies a different id, their updates should now be only for that new id.
  6. Updates for the id that one client requested are sent only to that one client (not to the other clients).

If that's what you really want, here's a way to structure that.

const wss = new WebSocket.Server({port: 10001});

// make database connection that all users share
client.connect();

wss.on('connection', function connection(ws) {
// these variables are unique to each ws connection
let interval, query;

// when webSocket closes, stop any current interval timer associated with this webSocket
ws.on('close', function() {
if (interval) {
clearInterval(interval);
}
});

// when we get an id, start querying for updates on that id
ws.on('message', function incoming(id) {
console.log(`received: ${id}`);
query = {
text: "SELECT id,state,users_list_name,user_win,timer_stamp FROM products WHERE id = " + parseInt(id) + " AND circle = 1 ORDER BY CASE WHEN state = \'available\' THEN \'1\' WHEN state = \'soon\' THEN \'2\' WHEN state = \'expired\' THEN \'3\' END",
};
// if interval is not already going, start it
if (!interval) {
interval = setInterval(function() {
client.query(query, (err, res) => {
if (err) {
console.log(err);
console.log(query);
} else {
// send data to just the one client that this timer is for
ws.send(JSON.stringify(res.rows));
}
});
}, 300);
}
});
});

Now, some comments:

  1. Polling the database on a short time interval with a separate polling loop for every single client simply will not scale at all. You will have serious database scale issues. You really need a better design here, but since we don't know the overall requirements and architecture of your application, we don't have enough info to know what to suggest. Probably you want to leverage notifications in a database that tell you when data has changed rather than you polling it on a short interval on behalf of every single client.

  2. I could find no reason for the lookup data structure. Your comments say that you want to send updates to ONE specific client, the one that requested that id. That can be done with ws.send().

  3. This code assumes that the client variable represents a connection to your database that each of the setIntervals for each connected client can all share. That's why that code was moved out of the wss.on('connection', ...) event handler.

  4. I switched to the more common terminology of wss to refer to the server instance and ws to refer to the webSocket for a particular connected client.

  5. ws.send() is how you send to a connected client. I still don't know what you were doing with op.id. Looking at the doc for the ws library, that doesn't appear to be something you can use to send to.

  6. Your code (and this code) creates a separate setInterval() timer for every webSocket client that connects and it uses a very short interval time. This will not scale. At worst, the interval time needs to be lengthened into multiple seconds (depending upon desired target scale). At best, you need to stop polling the database entirely and use some other mechanism in the database for getting notifications when data has been changed.

Sending messages to specific user with Spring Websocket

Can you see that the client subscribes successfully to your endpoint?

I think you are missing the first / in the client code 'user/queue/greetings' should be '/user/queue/greetings'



Related Topics



Leave a reply



Submit