Question

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?

Was it helpful?

Solution

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.

OTHER TIPS

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

Cheers

The simplest, most elegant solution

It's as easy as:

client.emit("your message");

And that's it.

But how? Give me an example

What we all need is in fact a full example, and that's what follows. This is tested with the most recent socket.io version (2.0.3) and it's also using modern Javascript (which we should be all using by now).

The example is comprised of two parts: a server and a client. Whenever a client connects, it starts receiving from the server a periodic sequence number. A new sequence is started for each new client, so the server has to keep track of them individually. That's where the "I need to send a message to a particular client" comes into play. The code is very simple to understand. Let's see it.

Server

server.js

const
    io = require("socket.io"),
    server = io.listen(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. When one arrives, it adds that new client to a map so it can keep track of its sequence number. It also listens for that client's disconnect event, when it'll remove it from the map.

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 its current sequence number. It then increments it and stores the number back in the map. 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
npm install socket.io-client

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.

In 1.0 you should use:

io.sockets.connected[socketid].emit();

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');

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,

  1. io.sockets.connected[socketid].emit(); OR
  2. io.eio.clients[socketid].emit(); OR
  3. 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)
    })

io.sockets.sockets[socket.id].emit(...) worked for me in v0.9

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'});

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/

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top