Socket.io: Namespaces, channels & co
Asked Answered
J

2

29

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?

Jeffersonjeffery answered 22/11, 2012 at 0:39 Comment(0)
C
30

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);
}
Crooked answered 22/11, 2012 at 2:35 Comment(6)
I've tried this. When using the second approach (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. So this means that I should use rooms. Anyway, I wonder what the semantic difference between a room and a namespace is? Why are there two concepts for the same (?) idea?Jeffersonjeffery
I believe it is so they can be managed separately, I did find a good write up on it though Socket.io NamespacesCrooked
This article is definitely a good read, but unfortunately it does not answer my question. I still don't understand when I should use namespaces, when rooms, and what the semantic difference is between them. And, moreover: How do I send a message to all clients, regardless of their namespace?Jeffersonjeffery
Thanks, this makes it very clear to me :-). So I'm going to stick with rooms in my example. So the bottomline is: Use rooms for different flavors of the same aspect, use namespaces for completely different aspects. Thanks :-))Jeffersonjeffery
Hello there @Golo Roden, a bit late but I've came across this by now. I think that in short, rooms should be used for dealing with same behaviour on socket across different places (chat rooms easiest example) But namespaces should be use to track different things such a real-time news feed vs a chat room. Hope add some more light to anyone. Thanks for question and answers!Paragraphia
this io.sockets.broadcast.emit is not correct, broadcast needs to know which socketID to exclude/ignore from emitting so you have two choices: 1) from global io -> io.sockets.in(namespace).socket(socketID).broadcast.emit("hello") or 2) from socket -> socket.broadcast.emit("hello")Puggree
F
4

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 :)

Fields answered 4/8, 2014 at 6:1 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.