Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Socket.io: Namespaces, channels & co

I have a Node.js web server that runs a socket server on top, which was created using Socket.io. Basically, this works.

What I now want to achieve is that the clients that connect are clustered in groups. So there might be some clients which make up group A and some other clients which make up group B. They shall select to which group they belong by adressing a specific URL, either localhost:3000/A or localhost:3000/B.

In Socket.io I now want to send messages to all clients in group A or to all clients in group B or to all clients, without looking at their group.

It's basically like having a chat with rooms, and you have either messages for all clients within a specific room, or for any client, no matter what room he is in.

What is the best way to design such a system using Socket.io?

I have been trying using namespace so far, which basically works for creating groups A and B, but then I lose the ability to send messages to all clients, no matter what room they are in. At least I don't know how to do this.

How should I model this? What are the right terms I should look for?

UPDATE: According to the answer of @sdedelbrock I could use namespace or rooms:

  • If use namespaces, I am not long able to send to everybody, regardless of their namespace. This is because io.sockets is a shortcut to io.of(''), which of course does not match the namespace any longer.
  • This means that I should use rooms, but I wonder what the semantic difference between a room and a namespace is.

To cut it short: Why are there two concepts for the same (?) idea?

like image 252
Golo Roden Avatar asked Nov 22 '12 00:11

Golo Roden


2 Answers

You could be using rooms so you would do the following to emit to everybody in a room

io.sockets.in('a').emit('inA', 'foo')

Then to emit to everybody you can use

io.sockets.emit('everyone','bar');

You can also use namespaces as well:

io.of('/b').emit('inB', 'buzz');

To emit to everyone except the user that triggered you would use:

io.sockets.broadcast.emit("hello");

[edit] Here is a more detailed answer:

The idea behind name-spacing is that it is handled separately from the other namespaces (even global). Think of it as if it was an entirely new socket.io instance, you can run new handshakes, fresh events, authorizations, etc without the different namespaces interfering with each other.

This would be useful for say /chat and /tracking where the connection event would have very different logic

Socket.io does all the work for you as if it is two separate instances, but still limits the information to one connection, which is pretty smart.

There might be a workaround in which you can broadcast to all the namespaces (example below). However in short you shouldn't be doing this, you should be using rooms.

for (var nameSpace in io.sockets.manager.namespaces){
  io.of(nameSpace).emit("messageToAll", message);
}
like image 148
Sdedelbrock Avatar answered Nov 02 '22 18:11

Sdedelbrock


This is a template application you can use (works for 9.16; not tested on 1.x but it should work):

var namespaces = [
    io.of('/ns1'),
    io.of('/ns2'),
    io.of('/ns3')
];

for (i in namespaces) {
    namespaces[i].on('connection',handleConnection(namespaces[i]));  
}

function handleConnection(ns) {
   return function (socket){ //connection
   console.log("connected ");
   socket.on('setUsername',setUsernameCallback(socket,ns));                       
   socket.on('disconnect', disconnectCallback(socket,ns));                        
   socket.on('messageChat',messageChatCallback(socket,ns));
   socket.on('createJoinRoom',createJoinRoomCallback(socket,ns));  

  };
}

function disconnectCallback(socket,ns) {
    return function(msg){
    console.log("Disconnected ");
    socket.broadcast.send("It works!");
  };
}

You could write other handles by yourself :)

like image 38
Marwen Trabelsi Avatar answered Nov 02 '22 17:11

Marwen Trabelsi