36

I´m going crazy with socket.io! Documentation is so bad it's simply not true.

I want to send a feedback to specific client over socket.io

My server side looks like this:

app.get('/upload', requiresLogin, function(request, response) {
    response.render('upload/index.jade');
    io.sockets.on('connection', function (socket) {
        console.log('SOCKET ID ' + socket.id);
        io.sockets.socket(socket.id).emit('new', 'hello');
    });
});

and the client side looks like this:

$(document).ready(function() {
    var socket = io.connect('http://localhost:80/socket.io/socket.io.js');
    socket.on('new', function (data) { 
        console.log(socket.id);
        console.log(data); 
        //$('#state').html(data.status);
    });
});

but the client does simply nothing. I have tried nearly everything. Can someone tell me what I am doing wrong, please! :(

keeri
  • 809
  • 2
  • 13
  • 19
krevativ
  • 530
  • 1
  • 8
  • 9

9 Answers9

53

to send a message to a specific client save every one that connects to the server in an Object.

var socketio = require('socket.io');
var clients = {};
var io = socketio.listen(app);

io.sockets.on('connection', function (socket) {
  clients[socket.id] = socket;
});

then you can later do something like this:

var socket = clients[sId];
socket.emit('show', {});
Philipp Kyeck
  • 18,402
  • 15
  • 86
  • 123
  • that doesnt work. i have made a simple test: var soc; io.sockets.on('connection', function (socket) { soc = socket; }); outside from every rout. and than in my upload function i have used soc.emit('news', 'bla') nothing happens.... – krevativ Aug 02 '11 at 16:00
  • as i said before: you can't send events while uploading a file. but this methods works and you can send messages to specific clients, when you have the corresponding id. – Philipp Kyeck Aug 02 '11 at 16:14
  • :-/ sorry i misunderstood you. so there is no way to trigger a message to a specific client from a route function? – krevativ Aug 02 '11 at 19:58
  • yes, there is. you have to save all clients that connect to your server in the clients-object (see example) and when you have the socket-id, you can access the socket directly through the object. but you CAN'T do that while uploading... – Philipp Kyeck Aug 02 '11 at 20:27
  • how would you recommend managing the object(once a client disconnects its O(n) to find the dead socket)... :-\ – Leon Fedotov Nov 07 '12 at 14:15
  • 1
    what exactly are you trying to do? delete the old connection? just do a `delete clients[socketId];` when the client disconnected and it'll be removed from `clients` hash. – Philipp Kyeck Nov 07 '12 at 15:02
  • This won't work with multiple nodejs processes using redis as a backend for synchronisation, since the clients are stored per process, and can't be accessed by other processes http://stackoverflow.com/a/12735608/262980 is idependent of the process – jigfox Dec 18 '14 at 09:06
  • @jigfox ok, but this wasn't in the question ... the answer also doesn't cook you an egg - no need to downvote it because of this :( – Philipp Kyeck Dec 19 '14 at 09:51
  • @pkyeck: no it doesn't cook an egg, but it provides a solution to problem, which doesn't work for everyone, so the other answer is better and therefor the down vote (so the IMHO better answer gets a chance to become most voted answer sometime) – jigfox Dec 22 '14 at 09:51
  • I don't know how much this solution is scalable from aspect of RAM consumption and maybe memory leaks. In newer versions of socket.io i think there is builtin support for something like that? This answer is from 2011 so maybe back then there was no support built in? – Srle Sep 08 '15 at 23:43
18

A couple of ways to send feedback to a specific client over socket.io include:

  • As stated by pkyeck, save all clients to an Object, so you can send to these specific clients later in your route handlers, e.g.:

    var sessionsConnections = {};
    sio.on('connection', function (socket) {
      // do all the session stuff
      sessionsConnections[socket.handshake.sessionID] = socket;
    });
    
  • or, use socket.io's built in support for rooms - subscribe each client to a room on connection and send via this room within route handlers, e.g.:

    sio.on('connection', function (socket) {
      // do all the session stuff
      socket.join(socket.handshake.sessionID);
      // socket.io will leave the room upon disconnect
    });
    
    app.get('/', function (req, res) {
      sio.sockets.in(req.sessionID).send('Man, good to see you back!');
    });
    

Acknowledgement:

http://www.danielbaulig.de/socket-ioexpress/#comment-1158

Note that both these example solutions assume that socket.io and express have been configured to use the same session store and hence refer to the same session objects. See the links above and below for more details on achieving this:

https://github.com/LearnBoost/socket.io/wiki/Authorizing

Brian Webster
  • 30,033
  • 48
  • 152
  • 225
Tom Rogers
  • 301
  • 2
  • 4
  • Just want to say that using the session id as a room was a great suggestion. Helped me solve a problem I was having, so thanks :) – Jason L. Dec 05 '12 at 15:31
  • 2
    seems like socket.io 1.0 has built in support for the room per socket approach: http://socket.io/docs/rooms-and-namespaces/ – Asaf Katz Jun 04 '14 at 15:22
  • The room should take care of clustering. Saving sockets in local memory like other answers can lead to memory leak and can't scale. – Taku Apr 14 '16 at 18:53
7

2 things

1) You should really place your io.sockets.on(..) outside your app/update route to prevent adding multiple listeners for clients.

2) io.sockets.socket(id); should not be used, it should have been socket.emit('new', 'hello')

3rdEden
  • 4,388
  • 1
  • 20
  • 18
  • okay great, this was also a problem io.connect('http://localhost:80/socket.io/socket.io.js'); but what when i want to send messages during the upload? then I need to store the client ID and use io.sockets.socket(socket.id).emit('new', 'hello'); or not? – krevativ Aug 02 '11 at 15:08
  • as far as i know the socket connection isn't disconnected while uploading a file via form. – Philipp Kyeck Aug 02 '11 at 15:23
  • okay great and the last question. is it possible die empty the message queue? when i reenter the view i receive all the old massages... – krevativ Aug 02 '11 at 15:46
  • @vboy which message queue are you talking about? The message queue that socket.io maintains internally for messages that are not received by the client? – 3rdEden Aug 03 '11 at 14:50
5

In socket.io 1.0, this is how it would work. It may work for lower versions, but I cannot guarantee it.

socket.to(socket_id_here).emit('new', 'hello');

This works because socket.io automatically adds a socket to a room with the socket's id on connection.

Also, if you plan to upgrade to version 1.0, there are a lot of changes to the api, so you'll sometimes have to change some code to make it work in 1.0.

Ferdi265
  • 2,879
  • 1
  • 17
  • 15
4

The correct way to do this in Socket.io 1.0+ is:

io.to(users_socket_id).emit('new', 'hello');

You can also substitute a room name for 'users_socket_id' to emit to a specific socket.io room.

Williz
  • 309
  • 1
  • 9
2

First of all, you cannot use socket.id on client side.

And then change the line

var socket = io.connect('http://localhost:80/socket.io/socket.io.js');

to

var socket = io.connect('http://localhost:80/');

Shekhar
  • 910
  • 1
  • 13
  • 23
0

I believe io.sockets.socket has been removed and has been a problem in Socket.IO (https://github.com/socketio/socket.io/issues/1618).

You can use io.sockets.connected[socket.id] and store the socket.id to reference with the user via username:

var usernames = {};
usernames[username] = socket.id;
// Sending the message
io.sockets.connected[usernames[username]].emit(...);

I don't see it anywhere on the documentation so I can see how this hasn't been answered. Also, if you don't have any reference via usernames, you can instead try:

users[socket.id] = socket.id;

to duplicate the key and value for easy access.

There is also possibly another way by using io.clients as described below, but I haven't used that method.

OTHER SOLUTION: Send message to specific client with socket.io and node.js

jsb
  • 80
  • 1
  • 4
0

Have you tried using?

var socket = io.connect('http://localhost:80/');
0

i tired with the latest version of node and socket.io below i am going to post complete code

  <ul id="messages"></ul>
<form action="">
  <input id="id1"  /><button>Send</button>
</form>
<script src="https://cdn.socket.io/socket.io-1.2.0.js"></script>
<script src="http://code.jquery.com/jquery-1.11.1.js"></script>
<script>

  var io = io.connect();
  $('form').submit(function(){
    io.emit('drumevent', $('#id1').val());
    $('#id1').val('');
    return false;
  });
  io.on('drumevent', function(msg){
  console.log(msg);



    $('#messages').append($('<li></li>').text(msg.message+'    quantity = '+msg.quantity));
  });
</script>

server side code

  var usernames = {};io.on('connection', function(socket){usernames["username"] = socket.id;
socket.on('drumevent', function(msg){     
var socketId = socket.id;io.to(socketId).emit('drumevent', data);
Adiii
  • 54,482
  • 7
  • 145
  • 148