I followed a different S/O answer to figure out how to communicate to my server that a client disconnected by using
var socket = io.connect(<your_url>, {
'sync disconnect on unload': true });
The problem is, since this is part of the original socket configuration, I can't tell from the server which of my clients actually disconnected. On my client-side, I display a list of usernames for all connected clients, so I need to know which username to remove from that list for the remaining clients.
server-side code that gets triggered when a client closes out is:
socket.on('disconnect', reason => {
console.log('user disconnected', reason);
});
but the "reason" variable turns out to just be a string that says: "transport close" with no information about the actual client that disconnected.
One approach I thought of was, whenever a client disconnects, the server can request a response from all connected clients and use that to send out an updated list every time, but this seems excessive. I'd much prefer to know which client disconnected when they disconnect, and simply broadcast the id of the newly disconnected client, so the other clients are able to update their respective user lists locally. When a new client joins, after all, I broadcast that client's username, so all clients can update locally - I'd like to use the same pattern when a client disconnects.
In short, does anyone know a way to, within the "sync disconnect on unload" configuration of socket.io, also send the client's ID on unload?
Turns out I needed to keep an array in the server of active participants, adding to it every time they connect.
let users = []
socket.on('join', data => {
data.id === socket.id
users.push(data)
})
socket.on('disconnect', reason => {
let user = users.find(u => u.id === socket.id)
// we emit an event from the server, not from a particular socket
io.emit('player disconnected', {
user
}
})
I am using version 0.9.4 (I can use any version as per your guidance)
in server (app.js), I am storing socket id like this:
var socket_ids = [];
io.sockets.on('connection', function(socket) {
socket_ids.push(socket.id); #This is how I am getting socket id. My real code logic is totally different, but getting socket id using socket.id;
socket.on('createNote', function(data) {
socket.broadcast.to(socket_ids[0]).emit('onNoteCreated', data);
});
});
In short, I have 4 people opened sessions, all 4 are different users.
When p1 sends message, it should reach p2 only.
When p3 sends message, it should reach p4 only.
Keeping the if..else logics aside(I am fine with that), when I am broadcasting message using socket id, the client/browser with that socket id is not receiving that message. Also, above above broadcast line of code(other lines are custom for SO) not giving errors but client not receiving.
But these clients/browsers receiving messages when broadcasted to everything.
Thanks.
With the latest socket.io version, this is how I would do it:
var sockets = [];
io.on("connection", function(socket){
// Store whole socket object.
// NOTE: You should probably loop through sockets array
// to see if a socket with this id already exists
sockets.push(socket);
socket.on("createNote", function(data){
sockets[0].emit("onNoteCreated", data);
});
});
Hope this helps
server side:
io.of('/lobby').on('connection', function(client) {
setInterval(function(){
io.to(client.id).emit('message','test');
},2000);
});
client side:
var ioLobby = io.connect('127.0.0.1:9001/lobby');
ioLobby.on('message',function(data){
console.log(data);
});
I'm trying to send a message to a specific client in socket.io version 1.2.1. I've verified that the socket joins the default room on the server side, but its not being triggered on the client side. Any ideas?
The line io.to(client.id) will only work if that user has first joined a room with that same name. You need something like
io.on('connection', function(socket){
socket.join('some room');
});
and then you can call io.to
io.to('some room').emit('some event'):
I compromised and ended up using
socket.emit()
The only downside in comparison is requiring a ref to the socket you're emitting to.
I have a socket.io connection to connect to server and client,
It work fine.
Now when I try to reconnect it on disconnect from server it get connected but then socket.on('message' doesnt get fired any more.
I checked it from server side it is pushing that message.
Please suggest me some thing I am out of ideas now.
I am sure that problem is on client side socket.on message
Client side code
var socket = new io.Socket('some host name',{port:80,rememberTransport:true});
socket.on('connect', function(){
clearInterval(socketInterval);
});
socket.on('message', function(obj)
{
alert("meg from server");
});
socket.on('disconnect', function()
{
socketInterval=setInterval("socket.connect()",5000);
});
socket.connect();
I don't know node.js, but it looks like syntax error, haven't you forgot the right paratheses?
socket.on('connect', function(){
clearInterval(socketInterval);
});
socket.on('message', function(obj)
{
alert("meg from server");
});
socket.on('disconnect', function()
{
socketInterval=setInterval("socket.connect()",5000);
});
it would appear that the "problem" most likely is on the server side. The server has two ways to send messages to the client (emit and broadcast). If you are doing a one to one message, most people use emit. I am assuming that you built a chat server which stores the sessionIds of the client. It works fine with the initial connection because the server has the correct sessionId, but let's say connection is lost and you reestablish connection, now the server tries to send a message to the client. If your server stored the initial sessionId, say in an array, and attempts to use the original sessionId to emit a message, it will fail because reconnection causes a new sessionId to be created.
The solution in this case is to remove the previous sessionId from the array and add the new sessionId upon reconnection.
I'm working with socket.io and node.js and until now it seems pretty good, but I don't know how to send a message from the server to an specific client, something like this:
client.send(message, receiverSessionId)
But neither the .send() nor the .broadcast() methods seem to supply my need.
What I have found as a possible solution, is that the .broadcast() method accepts as a second parameter an array of SessionIds to which not send the message, so I could pass an array with all the SessionIds connected at that moment to the server, except the one I wish send the message, but I feel there must be a better solution.
Any ideas?
Ivo Wetzel's answer doesn't seem to be valid in Socket.io 0.9 anymore.
In short you must now save the socket.id and use io.sockets.socket(savedSocketId).emit(...) to send messages to it.
This is how I got this working in clustered Node.js server:
First you need to set Redis store as the store so that messages can go cross processes:
var express = require("express");
var redis = require("redis");
var sio = require("socket.io");
var client = redis.createClient()
var app = express.createServer();
var io = sio.listen(app);
io.set("store", new sio.RedisStore);
// In this example we have one master client socket
// that receives messages from others.
io.sockets.on('connection', function(socket) {
// Promote this socket as master
socket.on("I'm the master", function() {
// Save the socket id to Redis so that all processes can access it.
client.set("mastersocket", socket.id, function(err) {
if (err) throw err;
console.log("Master socket is now" + socket.id);
});
});
socket.on("message to master", function(msg) {
// Fetch the socket id from Redis
client.get("mastersocket", function(err, socketId) {
if (err) throw err;
io.sockets.socket(socketId).emit(msg);
});
});
});
I omitted the clustering code here, because it makes this more cluttered, but it's trivial to add. Just add everything to the worker code. More docs here http://nodejs.org/api/cluster.html
each socket joins a room with a socket id for a name, so you can just
io.to('socket#id').emit('hey')
docs: http://socket.io/docs/rooms-and-namespaces/#default-room
The simplest, most elegant way
verified working with socket.io v3.1.1
It's as easy as:
client.emit("your message");
And that's it. Ok, but how does it work?
Minimal working example
Here's an example of a simple client-server interaction where each client regularly receives a message containing a sequence number. There is a unique sequence for each client and that's where the "I need to send a message to a particular client" comes into play.
Server
server.js
const
{Server} = require("socket.io"),
server = new Server(8000);
let
sequenceNumberByClient = new Map();
// event fired every time a new client connects:
server.on("connection", (socket) => {
console.info(`Client connected [id=${socket.id}]`);
// initialize this client's sequence number
sequenceNumberByClient.set(socket, 1);
// when socket disconnects, remove it from the list:
socket.on("disconnect", () => {
sequenceNumberByClient.delete(socket);
console.info(`Client gone [id=${socket.id}]`);
});
});
// sends each client its current sequence number
setInterval(() => {
for (const [client, sequenceNumber] of sequenceNumberByClient.entries()) {
client.emit("seq-num", sequenceNumber);
sequenceNumberByClient.set(client, sequenceNumber + 1);
}
}, 1000);
The server starts listening on port 8000 for incoming connections. As soon as a new connection is established, that client is added to a map that keeps track of its sequence number. The server also listens for the disconnect event to remove the client from the map when it leaves.
Each and every second, a timer is fired. When it does, the server walks through the map and sends a message to every client with their current sequence number, incrementing it right after. That's all that is to it. Easy peasy.
Client
The client part is even simpler. It just connects to the server and listens for the seq-num message, printing it to the console every time it arrives.
client.js
const
io = require("socket.io-client"),
ioClient = io.connect("http://localhost:8000");
ioClient.on("seq-num", (msg) => console.info(msg));
Running the example
Install the required libraries:
npm install socket.io#3.1.1 socket.io-client#3.1.1
Run the server:
node server
Open other terminal windows and spawn as many clients as you want by running:
node client
I have also prepared a gist with the full code here.
Well you have to grab the client for that (surprise), you can either go the simple way:
var io = io.listen(server);
io.clients[sessionID].send()
Which may break, I doubt it, but it's always a possibility that io.clients might get changed, so use the above with caution
Or you keep track of the clients yourself, therefore you add them to your own clients object in the connection listener and remove them in the disconnect listener.
I would use the latter one, since depending on your application you might want to have more state on the clients anyway, so something like clients[id] = {conn: clientConnect, data: {...}} might do the job.
You can use
//send message only to sender-client
socket.emit('message', 'check this');
//or you can send to all listeners including the sender
io.emit('message', 'check this');
//send to all listeners except the sender
socket.broadcast.emit('message', 'this is a message');
//or you can send it to a room
socket.broadcast.to('chatroom').emit('message', 'this is the message to all');
In 1.0 you should use:
io.sockets.connected[socketid].emit();
Whatever version we are using if we just console.log() the "io" object that we use in our server side nodejs code, [e.g. io.on('connection', function(socket) {...});], we can see that "io" is just an json object and there are many child objects where the socket id and socket objects are stored.
I am using socket.io version 1.3.5, btw.
If we look in the io object, it contains,
sockets:
{ name: '/',
server: [Circular],
sockets: [ [Object], [Object] ],
connected:
{ B5AC9w0sYmOGWe4fAAAA: [Object],
'hWzf97fmU-TIwwzWAAAB': [Object] },
here we can see the socketids "B5AC9w0sYmOGWe4fAAAA" etc. So, we can do,
io.sockets.connected[socketid].emit();
Again, on further inspection we can see segments like,
eio:
{ clients:
{ B5AC9w0sYmOGWe4fAAAA: [Object],
'hWzf97fmU-TIwwzWAAAB': [Object] },
So, we can retrieve a socket from here by doing
io.eio.clients[socketid].emit();
Also, under engine we have,
engine:
{ clients:
{ B5AC9w0sYmOGWe4fAAAA: [Object],
'hWzf97fmU-TIwwzWAAAB': [Object] },
So, we can also write,
io.engine.clients[socketid].emit();
So, I guess we can achieve our goal in any of the 3 ways I listed above,
io.sockets.connected[socketid].emit();
OR
io.eio.clients[socketid].emit();
OR
io.engine.clients[socketid].emit();
You can do this
On server.
global.io=require("socket.io")(server);
io.on("connection",function(client){
console.log("client is ",client.id);
//This is handle by current connected client
client.emit('messages',{hello:'world'})
//This is handle by every client
io.sockets.emit("data",{data:"This is handle by every client"})
app1.saveSession(client.id)
client.on("disconnect",function(){
app1.deleteSession(client.id)
console.log("client disconnected",client.id);
})
})
//And this is handle by particular client
var socketId=req.query.id
if(io.sockets.connected[socketId]!=null) {
io.sockets.connected[socketId].emit('particular User', {data: "Event response by particular user "});
}
And on client, it is very easy to handle.
var socket=io.connect("http://localhost:8080/")
socket.on("messages",function(data){
console.log("message is ",data);
//alert(data)
})
socket.on("data",function(data){
console.log("data is ",data);
//alert(data)
})
socket.on("particular User",function(data){
console.log("data from server ",data);
//alert(data)
})
As of version 1.4.5, be sure you provide a properly prefixed socketId in io.to().
I was taking the socketId the Client logged to debug and it was without prefix so I ended up searching forever till I found out! So you might have to do it like this if the Id you have is not prefixed:
io.to('/#' + socketId).emit('myevent', {foo: 'bar'});
io.sockets.sockets[socket.id].emit(...) worked for me in v0.9
Also you can keep clients refferences. But this makes your memmory busy.
Create an empty object and set your clients into it.
const myClientList = {};
server.on("connection", (socket) => {
console.info(`Client connected [id=${socket.id}]`);
myClientList[socket.id] = socket;
});
socket.on("disconnect", (socket) => {
delete myClientList[socket.id];
});
then call your specific client by id from the object
myClientList[specificId].emit("blabla","somedata");
Socket.IO allows you to “namespace” your sockets, which essentially means assigning different endpoints or paths.
This might help:
http://socket.io/docs/rooms-and-namespaces/