node.js net module pings and messages not happening - node.js

I have two node.js applications running side by side on my server and I wan't to send server-side messages between them in a light weight manner using native node.js (v0.10.33) module net
I intend the first application to send messages to the second. I see the console log listening...,
In the first application:
var push='';
var net=require('net');
var server=net.createServer(function(p){
p.on('error',function(err){console.log(err);});
push=p;
setInterval(function(){push.write(JSON.stringify({'f':'ping','data':'stay alive'}));},1000);
});
server.listen(8008,function(){console.log('listening...')});
//a real message might be sent later in the application (this example would need a setTimeout)
push.write(JSON.stringify({'f':'msg','data':'Hello World'}));
In the second application I see the console log open
var net=require('net');
var pull=new net.Socket();
pull.connect(8008,'127.0.0.1',function(){console.log('open');
pull.on('data',function(_){
_=JSON.parse(_);
if(_.f==='ping'){console.log('!!!ping!!!');}
else{console.log(_.data);}
});
pull.on('error',function(err){console.log('pull: '+err);});
});
I do not see any other activity though (no pings, and later after the open event, no hello world) and no errors.
If I inspect with console.dir(pull) I don't see events for accepting data ie: ondata or onmessage
What is wrong?

Unfortunately, I must point out that this messaging scheme is fundamentally broken. You're using TCP, which provides a stream of bytes, not messages.
Despite the fact that TCP sends its data over IP packets, TCP is not a packet protocol. A TCP socket is simply a stream of data. Thus, it is incorrect to view the data event as a logical message. In other words, one socket.write on one end does not equate to a single data event on the other. A single data event might contain multiple messages, a single message, or only part of a message.
The good news is this is a problem already solved many times over. I'd recommend either:
Using a library meant for passing JSON messages over TCP.
Using something like redis as a pub-sub messaging solution (this option makes your app much easier to scale)
If you know that your two apps will always run on the same machine, you should use node's built-in IPC mechanism.

Related

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.

How to measure Websocket backpressure or network buffer from client

I am using the ws Node.js package to create a simple WebSocket client connection to a server that is sending hundreds of messages per second. Even with a simple onMessage handler that just console.logs incoming messages, the client cannot keep up. My understanding is that this is referred to as backpressure, and incoming messages may start piling up in a network buffer on the client side, or the server may throttle the connection or disconnect all-together.
How can I monitor backpressure, or the network buffer from the client side? I've found several articles speaking about this issue from the perspective of the server, but I have no control over the server and need to know just how slow is my client?
So you don't have control over the server and want to know how slow your client is.(seems like you already have read about backpressure). Then I can only think of using a stress tool like artillery
Check this blog, it might help you setting up a benchmarking scenario.
https://ma.ttias.be/benchmarking-websocket-server-performance-with-artillery/
Add timing metrics to your onMessage function to track how long it takes to process each message. You can also use RUM instrumentation like from the APM providers -- NewRelic or Appdynamics for paid options or you could use free tier of Google Analytics timing.
If you can, include a unique identifier for correlation between the client and server for each message sent.
Then you can correlate for a given window how long a message took to send from the server and how long it spent being processed by the client.
You can't get directly to the network socket buffer associated with your websocket traffic since you're inside the browser sandbox. I checked the WebSocket APIs and there's no properties that expose receive buffer information.
If you don't have control over the server, you are limited. But you could try some client tricks to simulate throttling.
This heavily assumes you don't mind skipping messages.
One approach would be to enable the socket, start receiving events and set your own max count in a in-memory queue/array. Once you reach a full queue, turn off the socket. Process enough of the queue, then enable the socket again.
This has high cost to disable/enable the socket, as well as the loss of events, but at least your client will not crash.
Once your client is not crashing, you can put some additional counts on timestamp and the queue size to determine the threshold before the client starts crashing.

Is it possible to have server to server communication with websockets?

I'm trying to have 2 servers communicate with each other, I'm pretty new to websockets so its kind of confusing. Also, just to put it out there, i'm not trying to do this: websocket communication between servers;
My goal here is to basically use a socket to read data from another server (if this is possible?) I'll try to easily explain more below;
We'll assume there is a website called https://www.test.com (going to this website returns an object)
With a normal HTTP request, you would just do:
$.get('https://www.test.com').success(function (r) {
console.log(r)
})
And this would return r, which is an object thats something like this {test:'1'};
Now from what I understand with websockets, is that you cannot return data from them because you don't actually 'request' data, you just send data through said socket.
Since I know what test.com returns, and I know all of the headers that i'm going to need, is it possible to just open a socket with test.com and wait for that data to be changed without requesting it?
I understand how client-server communication works with socketio/websockets im just not sure if its possible to do server-server communication.
If anyone has any links to documentation or anything trying to help explain, it would be much appreciated, I just want to learn how this works. (or if its even possible)
Yes, I you can do what (assuming I understood your needs correctly). You can establish a websocket connection between two servers and then either side can just send data to the other. That will trigger an event at the other server and it will receive the sent data as part of that event. You can do this operation either direction from serverA to serverB or vice versa or both.
In node.js, everything is event driven. So, you would establish the webSocket connection and then just set up an event handler to be triggered when data arrives. The other server can then just send new data whenever it has updated data to send. This is referred to as the "push" model. So, rather than serverA asking serverB is it has any new data, you establish the webSocket connection and serverB just sends new data to serverA whenever that new data is available. Done correctly, this is both more efficient and more timely (as there is no polling interval and no cycles wasted asking for data when there is nothing new).
The identical model can be used between servers or client to server. The only difference with the client/server model is that the webSocket must be initially established client to server. With the server to server model, either server can initiate the connection.
You can think of a webSocket connection like establishing a phone call. Once the phone call is established, either side can just say something and the other end hears what they're saying. The webSocket connection is similar. Once its established, either side can just send some data to the other end and the other end will receive it. It's an open pipeline ready to have data sent either way. In node.js, when data arrives on that pipeline, it triggers and event so the listener will get that event and see the data that was sent.

How to asynchronously send data with socketio to a web client?

The following situation:
Web client: Using JavaScript socketio to listen for incoming messages (= JavaScript).
Web server: Using flask-socketio with eventlet to send data (= Python).
Everything works if the client sends a message to the server. The server receives the messages. Example:
socketio = SocketIO(app, engineio_logger=True, async_mode="eventlet")
#socketio.on("mymsg")
def handle_event(message):
print("received message: " + str(message))
Unfortunately the other way around does not work - to some extent. I have a thread producing live data about 5 to 10 times a second the web frontend should display. It should be sent to the client.
First: It does not work at all if the thread producing the data tries to invoke sockeito.emit() directly. The reason for that is unclear to me but somehow plausible as flask-socketio with eventlet follows different async models, as the documentation says.
Second: Decoupling classic threads from the async model of flask/eventlet works to some extent. I attempt to use an eventlet queue for that. All status data my thread produces is put into the queue like this:
statusQueue.put(statusMsg)
This works fine. Debugging messages show that this is performed all the time, adding data after data to the queue.
As the documentation of flasks tells I'm adviced to use socketio.start_background_task() in order to get a running "thread" in a compatible mode to the async model socketio uses. So I am using this code:
def emitStatus():
print("Beginning to emit ...")
while True:
msg = statusQueue.get()
print("Sending status packet: " + str(msg))
socketio.emit("status", msg, broadcast=True)
statusQueue.task_done()
print("Sending status packet done.")
print("Terminated.")
socketio.start_background_task(emitStatus)
The strange thing where I'm asking you for help is this: The first call to statusQueue.get() blocks as expected as initially the queue is empty. The first message is taken from the queue and sent via socketio. Debug messages at the client show that the web client receives this message. Debug messages at the server show that the message is sent successfully. But: As soon as the next statusQueue.get() is invoked, the call blocks indefinitely, regardless of how many messages get put into the queue.
I'm not sure if this helps but some additional information: The socketio communication is perfectly intact. If the client sends data, everything works. Additionally I can see the ping-pongs both client and server play to keep the connections alive.
My question is: How can I properly implement a server that is capable of sending messages to the client asynchronously?
Have a look at https://github.com/jkpubsrc/experiment-python-flask-socketio for a minimalistic code example featuring the Python-Flask server process and a JQuery based JavaScript client.
(FYI: As these are status messages not necessarily every message needs to arrive. But I very much would like to receive at least some messages not only the very first message and then no other message.)
Thank you for your responses.
I left two solutions to make the code work as pull requests.
Basically, the answer is: you choose one technology and stick a process with it:
Going async_mode=threading? Great, use stdlib Queue. Don't import eventlet unless you have to.
Going async_mode=eventlet? Also great, use eventlet Queue and don't forget that stdlib time.sleep or socket IO will block everything else, fix with eventlet.monkey_patch()
If you must use both eventlet and threading, the best approach is to let them live in separate OS processes and communicate via local socket. It's extra work, but it is very robust and you know how it works and why it will not break.
With good knowledge of both eventlet and native threads you can carefully mix them into working code. As of 2018-09, mixing doesn't work in friendly obvious way, as you already found. Sorry. Patches are welcome.

SocketIO can't send new message until first will be delivered

Situation:
User has sent image, after image, he will send message. While the second user does not receive a picture, the message will not be sended.
How to send messages normally, like in normal chat?
I have found, that there are "async" module for node.js, but how to use it with Socket IO?
You could simply pass every messages in a queue. So each messages must wait for the first one to be send before passing to the next.
Although, here in your case. I don't think waiting for an image to be sent is wise - this will make your chat unresponsive.
Rather, use simple text image message. Once you receive this, put a placeholder in the chat where you'll load the image when you received it (displaying a loader meanwhile). This will allow you to continue the chat without being blocked by a long IO process to finish.
Socket.IO uses a single WebSocket connection which only allows for sending one item at a time. You should consider sending that image out-of-band on a separate WebSocket, or via another method.
I have a similar situation where I must stream continuous binary data and signaling messages. For this, I use BinaryJS to set up logical streams which are mirrored on both ends. One stream is used for binary streaming, and the other is used for RPC. Unfortunately, Socket.IO cannot use arbitrary streams. The only RPC library that seems to work is rpc-stream. The RPC functionality isn't nearly as powerful as Socket.IO (in particular when dealing with callbacks), but it does work well.

Resources