Socket.io broadcast to namespaces in client side - node.js

I have two namespaces which i created on the server side. The root namespace and a GroupChatEvents namespace.
In the client, I want to broadcast a message to both namespaces. Is that possible?
Client side code
var socket = io();
var GroupChatEventsSocket = io('/GroupChatEvents');
GroupChatEventsSocket.emit and socket.emit both only send to their specific namespaces. How can I broadcast to multiple specific namespaces?
Thanks

There is no ability to broadcast directly to a namespace from the client. Instead, you can create a message that you send to the server that tells the server which namespaces you want to broadcast to and then create a listener for that message on the server that will do it. Remember, there are no client-to-client connections in webSocket/socket.io. All connections are client to server.
So, if you want something sent to another client, you have to ask the server to do it for you. This is true whether sending to a single client or broadcasting to all clients connected to a particular namespace.
How can I broadcast to multiple specific namespaces?
Create a message you can send to the server that specifies the message content and the list of namespaces you want it sent to. Then, implement a listener for that message on the server and when it receives that it can take the desired message and send it to each of the desired namespaces.
Just remember that unless you have some sort of authentication for who is allowed to do this that anyone might be able to connect to your server and do this type of broadcast.

Related

Understanding the various contexts of the emit method

I am trying to understand the contexts of each of the following:
io.emit
io.socket.emit
io.sockets.emit
socket.emit
sockets.emit
socket.broadcast.emit
From what I understand:
The socket variable represents a single connection currently being communicated with.
The io variable represents the collection of socket variables
So far I've come up with the following. I have not figured out what the 2nd and 5th option are for. So maybe they do not exist. However, I am not sure what the difference is between the 1st and 3rd option:
io.emit - sends a message to all clients
io.socket.emit
io.sockets.emit - sends a message to all clients
socket.emit - sends a message to a single client
sockets.emit
socket.broadcast.emit - sends to all clients except sender
Is the 2nd and 5th option ever used? What is the difference between the 1st and the 3rd option?
The ones that I see that are documented are:
io.emit() - send to all connected clients
io.sockets.emit() - send to all clients in the "/" namespace
io.to(roomName).emit() - send to all clients in a particular room
io.in(roomName).emit() - .in() is the same as .to()
io.of(nsp).emit() - send to all clients in a particular namespace
io.of(nsp).to(room).emit() - send to clients in a namespace that are in a room
namespace.emit() - send to all clients in a particular namespace
socket.emit() - send to single client
socket.broadcast.emit() - send to all connected clients except socket
io.sockets is the default / namespace so it's a special case of io.of('/'). So, io.sockets.emit() is just emitting to a namespace as in io.of('/').emit().
If your clients aren't connecting to any custom namespaces, then all your client connections will be in the / namespace so io.emit() and io.sockets.emit() will end up doing the same thing. But, if you have any clients connecting to a custom namespace, then io.sockets.emit() will only be sending to sockets in the / namespace whereas io.emit() will send to all connected clients regardless of namespace.
I'm not aware of a sockets variable or a io.socket property. If they actually exist, they do not appear to be documented and I would not recommend using them.
Is the 2nd and 3rd option ever used?
I'm not aware of support for io.socket.emit(). io.sockets.emit() broadcast to all clients connected to the default namespace which does have a use when there are other namespaces being used.
What is the difference between the 1st and the 3rd option?
As I explained above, there is a different between io.emit() and io.sockets.emit() when there are any clients connecting to a custom namespace.
Read the Documentation as well as the answers to this question. It has everything you need.

Multiple websockets onto multiple servers: how do they communicate?

I have a node server accepting websocket connections from the clients. Each client can broadcast a message to all of the other clients.
UPDATE: I am using https://github.com/websockets/ws as my library of choice.
At the moment, the server has an array with all of the connections. Each connection has a tabId. When one of the client emits a message, I go through all of the connections and check: if the connection's tabId doesn't match, I send the message to the client.
For loading issues, I am facing the problem of having to have more than one server. So, there will be say two servers, each one with a number of clients.
How do I make sure that a message gets broadcast to all of the websocket clients, and not only the ones connected to the same server?
One possible solution I thought is to have the connections stored on a database, where each record has the tabId and the serverId. However, even a simple broadcast gets tricky as messages to "local" sockets are easy to broadcast (the socket is local and available) whereas messages to "remote" sockets are tricky, and would imply intra-server communication.
Is there a good pattern to solve this? Surely, this is something that people face every day.
You could use a messagequeue like RabbitMQ.
When a client logs in to your server, create a consumer which listens to a queue which will receive messages directed to that particular client. And when the clients are sending messages, just use a publisher to publish them to the recipients queue.
This way it doesn't matter and you don't need to know on which nodes the clients are on, or if they jump from a node to another.

How to send data from client to only socket server

I know that if I emit data on a socket, the data would be emitted to the all connected clients.
io.emit("test", data)
For instance if I run the command above, actually the data reaches to the all clients. But only test channel listeners handle it.
To prevent that, I use rooms. I use code like the following:
io.in("test").emit(data)
So, what if a client send data to the server, then will data be reached to the all clients?
Note: I also use socket.io-redis to make cluster.
This code will send to all client in "roomName"
io.to(roomName).emit('new msg', {data:'hello every clients'});

Using socket.io-redis & multiple servers/processes. How do I send a message to a specific socket ID with a callback?

I have multiple processes & servers, and am using socket.io-redis with session affinity (on Heroku).
When a client connects, I store a map of the client's user ID to the client's socket ID in Redis. Upon disconnecting, I delete the client's user ID from Redis.
I would like to be able to push a message to a client by looking up the client's socket ID, then sending a message to the specific socket ID.
One way to do this is io.to(socketId).emit(...). However, this does not allow me to send a callback with the message, which I would really like because I want to have confirmation of message receipt.
Another way I have found is io.connected[socketId].emit(...). The problem with this is that it does not scale to multiple servers, since the io.connected object may not necessarily be the same on every server since it only records sockets that the server itself is connected to. This solution does allow callbacks, however.
Is there a way to solve this so I can emit messages to a specific socket ID from any server or process, and also send a callback with the message?

How does socket.io send messages across multiple servers?

The Socket.io API has the ability to send messages to all clients.
With one server and all sockets in memory, I understand how that server one can send a message to all its clients, that's pretty obvious. But what about with multiple servers using Redis to store the sockets?
If I have client a connected to server y and client b connected to server z (and a Redis box for the store) and I do socket.broadcast.emit on one server, the client on the other server will receive this message. How?
How do the clients that are actually connected to the other server get that message?
Is one server telling the other server to send a message to its connected client?
Is the server establishing its own connection to the client to send that message?
Socket.io uses MemoryStore by default, so all the connected clients will be stored in memory making it impossible (well, not quiet but more on that later) to send and receive events from clients connected to a different socket.io server.
One way to make all the socket.io servers receive all the events is that all servers use redis's pub-sub. So, instead using socket.emit one can publish to redis.
redis_client = require('redis').createClient();
redis_client.publish('channelName', data);
And all the socket servers subscribe to that channel through redis and upon receiving a message emit it to clients connected to them.
redis_sub = require('redis').createClient();
redis_sub.subscribe('channelName', 'moreChannels');
redis_sub.on("message", function (channel, message) {
socket.emit(channel, message);
});
Complicated Stuff !! But wait, turns out you dont actually need this sort of code to achieve the goal. Socket.io has RedisStore which essentially does what the code above is supposed to do in a nicer way so that you can write Socket.io code as you would write for a single server and will still get propagated over to other socket.io server through redis.
To summarise socket.io sends messages across multiple servers by using redis as the channel instead of memory.
There are a few ways you can do this. More info in this question. A good explanation of how pub/sub in Redis works is here, in Redis' docs. An explanation of how the paradigm works in general is here, on Wikipedia.
Quoting the Redis docs:
SUBSCRIBE, UNSUBSCRIBE and PUBLISH implement the Publish/Subscribe
messaging paradigm where (citing Wikipedia) senders (publishers) are
not programmed to send their messages to specific receivers
(subscribers). Rather, published messages are characterized into
channels, without knowledge of what (if any) subscribers there may be.
Subscribers express interest in one or more channels, and only receive
messages that are of interest, without knowledge of what (if any)
publishers there are. This decoupling of publishers and subscribers
can allow for greater scalability and a more dynamic network topology.

Resources