4

I'm designing a chat script which I test on my machine using different browsers. I'm tryng to send messages to specific users with socket.io, so here it is :

client:

socket.on('msgFromServer', function (data) {
     message = data['message'],
     from = data['from'],
     to = data['to'];               

    if($('#chatbox.'+from).dialog("isOpen") === true){
        $('#chatbox.'+from+' #messageOutput textarea.readOnly').text(message);      
    }   
    else if(($('#chatbox.'+from).dialog("isOpen") !== true)){
        createChatbox(from,to,message);
    }
});




server:

var users = {};
io.sockets.on('connection', function (socket) {
    if( ( users.hasOwnProperty(req.session.name) === false))
            users[req.session.name] = socket;

    socket.on('msgToServer', function (data) {
         for (var u in users){
              console.log("%s | %s",u,users[u]);
         }      

     });
}); 

Well, I'll talk about the structure of code related to the server. It is in charge of storing a user on a 'connection' event. The problem starts when I reload the page: it stores the user from browser A in the users object, if I reload and reconnect stores it again , but when I ask which are the contents of the users object in browser B ... the info is outdated and does not show the same result as when I ask which are the contents of the object in broser A, even though I'm trying to do some cheking of nullity to store vals if users is empty --> if( ( users.hasOwnProperty(req.session.name) === false)). Basically, what I need is a means of storing each socket resource in a container(in fact, doesn't necessarily needs to be an object) with an identifier(req.session.name) and to have such container available to all sessions in all browsers, so when server receives a message from browser A to browser B it could identify it and emit a response to browser B.

I got an I idea of what I wanted from https://github.com/generalhenry/specificUser/blob/master/app.js and http://chrissilich.com/blog/socket-io-0-7-sending-messages-to-individual-clients/

If you look carefully at the code... in chrissilich.com , the author states that we need to store the 'socket.id' (users[incoming.phonenumber] = socket.id), whereas in git generalhenry states we have to store the 'socket'(users[myName] = socket) resource. The latter is the correct one , because the values of socket.id tend to be the same in both browsers... and that value changes automatically , I don't know why is there... I suppose in earlier versions of node it worked that way.

Charlie
  • 183
  • 2
  • 14
  • Maybe try to store socket's logins in an object like clients[login]=socket.id ? So you always can send something to a particular socket like io.sockets.socket(clients[login]).emit(...) – Yury Solovyov Dec 27 '12 at 05:20
  • [link]http://chrissilich.com/blog/socket-io-0-7-sending-messages-to-individual-clients/ Im already doing that, the problem is that socket.id is the same in all browsers instead of socket. The link above demonstrates what you say. This link [link] https://github.com/generalhenry/specificUser/blob/master/app.js seems to work but I cant figure out how to store all users and to see them in all browsers ... – Charlie Dec 27 '12 at 14:31
  • why "socket.id is the same in all browsers" is problem to you? socket.id is generating on server, so it can't b browser-dependent – Yury Solovyov Dec 27 '12 at 15:11
  • Because as I understand, socket.id is used to track users. I login to the server with different accounts and browsers, so I send a event ,'msgToServer', when send a msg. On the server, what I print all users and their respective resources: 'socket'. If I use socket.id instead, when I do the same what I see as output is the same resource even though I have sent messages from different browsers and as you might expect... If I try to send an event(msg) from that resource (e.g. io.sockets.socket(clients[login])), which is the same in all browsers , such event(msg) is emitted to everyone – Charlie Dec 27 '12 at 16:21

1 Answers1

12

The problem is that socket.id identifies sockets, not users, so if an user has several tabs opened at same time, every tab would have different socket.id, so if you store only one socket.id for an user, every time you assign it, you overwrite previous socketid.

So, beside other possible problems, at least you need to do this or it won't work. I bet that you say about 1 socket for all browsers is that you overwrite the id every time (it happened to me when I started using Socket.IO)

As a general rule, remember that you manage CONNECTIONS and not USERS... an user can have more than one connection!.

On connection

function onConnection( socket ) {
    var arr = users[incoming.phonenumber] || null;
    if( !arr ) 
        users[incoming.phonenumber] = arr = [];
    if( arr.indexOf( socket.id ) === -1 )
        arr.push( socket.id ); // Assigns socket id to user
}

On disconnection

function onDisconnect( socket ) {
    var arr = users[incoming.phonenumber] || null;
    if( !arr ) return; // Should not happen since an user must connect before being disconnected
    var index = arr.indexOf( socket.id );
    if( index !== -1 )
        arr.splice( index, 1 ); // Removes socket id from user
}
JR.
  • 1,401
  • 1
  • 11
  • 9
  • Yes you are right. I solved a time ago. Basically the problem was that 'users' stored many sockets because I used the socket.id as a key, butwhen I reloaded the site... socket.id changed and stored once again the same user, so the solution is to change the key to something else (like a phone number, for instance). The code does not include all the issues, tho (just in case someone is in my situation). Thanks JR. for your answer. – Charlie Feb 04 '13 at 14:36