SocketIO: When to use io and whn to use socket? - node.js

I am learning node and socket io. I have been watching tutorials, at first it is good, but then, they start to mix up using socket.on(), socket.emit() and io.on(), io.emit(). It seems very confusing. Can anyone clear my concept that where to use io and where to use socket in nodejs?

Logically think of io as the top level socket.io engine manager. If you want to do something at the top level that either creates some sort of resource like a socket or a new namespace object or sends a message to all existing connections in a namespace, then you use io.
Once you create a resource like a socket, you then use that object itself to operate on it.
On the server, you use io when you want to listen for new connections or when you want to broadcast to all connections. There are a few other things you can also do with it.
In the client, you use io when you want to connect to a server.
You use socket when you want to communicate with one particular connection as that connection is represented by the socket object. So, each client connection has a socket object and you send or receive info to/from that client by using methods on the socket object.
So, const socket = io.connect(url) or as a shortcut const socket = io(url) will connect a client to a server and give you the client-side socket object.
io.on('connection, socket => { ... }) will listen for an incoming client connection on the server and give you the socket for that new connection.
socket.emit() sends a message to the other end of that particular socket (whether on client or server).
io.emit() on the server sends a messages to all current connected clients (technically all clients connected to the top level io namespace - there can be other namespaces).

Related

Is there any way for a socket io client to reuse an old socket that was previously closed?

Everytime a mobile user that is connected to my node.js, socket.io server leaves their browser (maybe checks instagram or something) the socket disconnects due to "transport close".
When they return I want them to reconnect using their old socket so they can receive buffered packets and have access to their old data stored in said socket.
What actually happens is that they reconnect and a new socket is created when the "connection" event is emitted in the server. The old socket is deleted too, unless I store it somewhere.
Are there any simple ways (config or something) to just reuse an old socket when a reconnection happens?
This post helped me a bit: reuse socket id on reconnect, socket.io, node.js. However it doesn't show me how to reuse the actual old socket.
Unfortunately after such event "transport close", by design the socket is destroyed.
So at this point you should look to other alternatives.
My suggestion is to introduce a new data structure which will store the messages in a list.
My proposal involves:
A map where the key is the user id and value is a list which contains all user messages.
You can store an offset to the structure which holds the list which marks the messages sent before the connection problem
On reconnect you lookup the map with the userid and retrieve the user messages

why is my socket.io server assigning new socket ids to clients or losing track of existing socket ids?

I'm developing a simple website, where the client and server communicate over web sockets. I'm using nodejs and the socket.io library for the socket communication
Specifically, my server works as a middleware between an mqtt broker and my client. So on one hand, my server connects with the mqtt broker to consume messages and on the other hand delivers these messages to the connected clients over web sockets. I'm using the node mqtt library for the mqtt communication.
My codebase is fairly large, so to give you a feeling of how my code looks like, I will show this example, which should be straightforward to understand:
const io = require("socket.io")(port);
handleRequests(io) {
io.on("connection", (socket) => {
logger.info(`New client connected: ${socket.id}`);
this.clients[socket.id] = { // track clients and subscribed topics
topic: '',
};
this.numberOfUsers++;
io.sockets.emit("onUser", this.numberOfUsers);
this.handleChange(socket);
this.addToSubscribedClients(socket);
this.removeFromSubscribedClients(socket);
this.handleDisconnect(socket);
this.sendMqttMessageToClient(socket);
});
}
This is my "main" function, where as you can see, I'm initializing an io object and using it later by passing it to the handleRequests function. Each time a new client connects, I'm calling the callback function where I call the five other functions and passing the socket object as a parameter, which should be fine I guess. I'm passing the socket object as a parameter because I need it to later call socket.emit in order to send back message to a specific client, since the socket object is unique for each client.
This works great until more than ~ 30 clients are connected. I'm trying to debug this for 2 weeks now and can't figure out why this is happening. I'm testing this by opening multiple tabs in my browser. I start with one client and then increase the number of clients/tabs. At some points, I notice that some clients receive no values from the server but other clients still do, which is incorrect since all clients should receive the values in real time.
I noticed that the clients, which are not receiving values have other ids than the ones stored on the server. I tested this with a simple console.log() on both clients and server. How this is happening? I'm very positive that I'm sending the ids correctly since there are other clients, which still receive values from the server. My guess is that the server is somehow disconnecting some clients automatically, because if a client reconnects then a new id will be assigned to it automatically.
Does anyone have any idea why this is happening? and why it works fine with the first ~30 clients and starts to occur when many clients are connected? This issue is very hard to debug since the code works fine for a small number of clients and no errors are thrown when the bug occurs, so I'm hoping that someone had this before.
Edit
Now I just found that i can print a reason for socket disconnection. When I do that, ping timeout is printed, which I don't understand because when I have one single or few clients connected then this error does not happen.

Socket.io broadcast to namespaces in client side

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.

Node clustering with websockets

I have a node cluster where the master responds to http requests.
The server also listens to websocket connections (via socket.io). A client connects to the server via the said websocket. Now the client choses between various games (with each node process handles a game).
The questions I have are the following:
Should I open a new connection for each node process? How to tell the client that he should connect to the exact node process X? (Because the server might handle incoming connection-requests on its on)
Is it possible to pass a socket to a node process, so that there is no need for opening a new connection?
What are the drawbacks if I just use one connection (in the master process) and pass the user messages to the respective node processes and the process messages back to the user? (I feel that it costs a lot of CPU to copy rather big objects when sending messages between the processes)
Is it possible to pass a socket to a node process, so that there is no
need for opening a new connection?
You can send a plain TCP socket to another node process as described in the node.js doc here. The basic idea is this:
const child = require('child_process').fork('child.js');
child.send('socket', socket);
Then, in child.js, you would have this:
process.on('message', (m, socket) => {
if (m === 'socket') {
// you have a socket here
}
});
The 'socket' message identifier can be any message name you choose - it is not special. node.js has code that when you use child.send() and the data you are sending is recognized as a socket, it uses platform-specific interprocess communication to share that socket with the other process.
But, I believe this only works for plain sockets that do not yet have any local state established yet other than the TCP state. I have not tried it with an established webSocket connection myself, but I assume it does not work for that because once a webSocket has higher level state associated with it beyond just the TCP socket (such as encryption keys), there's a problem because the OS will not automatically transfer that state to the new process.
Should I open a new connection for each node process? How to tell the
client that he should connect to the exact node process X? (Because
the server might handle incoming connection-requests on its on)
This is probably the simplest means of getting a socket.io connection to the new process. If you make sure that your new process is listening on a unique port number and that it supports CORS, then you can just take the socket.io connection you already have between the master process and the client and send a message to the client on it that tells the client where to reconnect to (what port number). The client can then contain code to listen for that message and make a connection to that new destination.
What are the drawbacks if I just use one connection (in the master
process) and pass the user messages to the respective node processes
and the process messages back to the user? (I feel that it costs a lot
of CPU to copy rather big objects when sending messages between the
processes)
The drawbacks are as you surmise. Your master process just has to spend CPU energy being the middle man forwarding packets both ways. Whether this extra work is significant to you depends entirely upon the context and has to be determined by measurement.
Here's ome more info I discovered. It appears that if an incoming socket.io connection that arrives on the master is immediately shipped off to a cluster child before the connection establishes its initial socket.io state, then this concept could work for socket.io connections too.
Here's an article on sending a connection to another server with implementation code. This appears to be done immediately at connection time so it should work for an incoming socket.io connection that is destined for a specific cluster. The idea here is that there's sticky assignment to a specific cluster process and all incoming connections of any kind that reach the master are immediately transferred over to the cluster child before they establish any state.

How to differentiate between each client connections in nanomsg socket library

Am using nanomsg library with
int sock = nn_socket (AF_SP, NN_PAIR);
assert (nn_bind (sock, url) >= 0);
Now I want to know how to differentiate each connection in server if client connects.
In Regular Linux TCP Socket, we will get new socket fd on every connection accept,
am expecting some thing like that in nanomsg.
In below link am trying to use - Pair (Two Way Radio)
http://tim.dysinger.net/posts/2013-09-16-getting-started-with-nanomsg.html
I don't think you can by default.
Messages come in, and whenever a message comes in, you process it. There's no additional data on which client connected, or where the message came from.
Thus, my suggestion would be to let every client identify itself by a UUID at the start of every message, or wrap the messages in a JSON like format of which one key is used by the client to identify itself.

Resources