How to catch TCP socket transmission failures in Node.JS? - node.js

When I write data to a TCP socket in Node, which is not closed but the client on the other side is not connected anymore (because of network failure for example), how do I know?
The socket's error event doesn't fire in this case for me. If I'm right, TCP gives up sending data, if there is absolutely no ACK packets from the other side, doesn't it? Or am I misunderstanding something?

As explained in the Nodejs Net documentation.
Socket events are close, connect, data, drain, end, error, lookup, and timeout.
Since you're not getting an error event, try listening to the end event which is emitted when the other end of the socket sends a FIN packet.
socket.on('end', () => console.log('socket has ended'))
Alternatively, if you expect a network failure or other unpredictable network edge cases on their end; you can always set a timeout and handle it that way.
socket.setTimeout(60000) // 60 seconds
socket.on('timeout', () => {
console.warn('socket has timed out')
socket.write('socket has timed out')
socket.end()
})

close event listeners are passed a hadError arg that indicates if the socket was closed because of a transmission error. For example:
socket.on('close', hadError => {
if (hadError) {
// Handle transmission error here
}
});

Related

How to properly destroy a socket so that it is ready to be called again after program exits? (Node.js)

He is a bit of code where a server is created to listen on port 2222:
import { createServer } from 'net';
const server = createServer((c) => {
c.setEncoding('utf8');
c.on('data', (data) => {
console.log('server', data);
c.write(data);
});
c.on('error', (e) => { throw e; });
});
server.listen(2222);
and the code to create a connection to the server to send a simple 'hello' that the server will respond back to. After 2 seconds, the socket gets destroyed.
import { createConnection } from 'net';
const socket = createConnection({ localPort: 9999, port: 2222, host: 'localhost' });
socket.setEncoding('utf8');
socket.on('data', (data) => {
console.log('socket data', data);
});
socket.on('connect', () => {
socket.write('hello');
});
socket.setTimeout(2000);
socket.on('timeout', () => { socket.destroy(); console.log('destroyed'); });
socket.on('error', (e) => { throw e; });
This code works well the first time it is called.
It will fail on subsequent calls with:
Error: connect EADDRINUSE 127.0.0.1:2222 - Local (0.0.0.0:9999)
errno: -48,
code: 'EADDRINUSE',
syscall: 'connect',
address: '127.0.0.1',
port: 2222
It took me a while to figure it out, but the problem comes from trying to bind the socket on an outbound port: localPort: 9999. Without specifying this parameter, the OS will select a free port, and the program won't crash.
When specifying it, a cooldown of ~15s is required before the socket being re-usable again.
Is there a way to properly destroy the socket so that it becomes immediately available again?
If not, is there a way to verify that the socket is "cooling down", but will eventually be available again? I'd like to distinguish the case where I just have to wait from the one where the socket has been actively taken by another process, and won't be released to the pool of free sockets.
Any theory on why the socket is not available after the program exists is welcome!
The socket is going into a CLOSE_WAIT state, so you have to wait until it is available again before you can reconnect. You can try to avoid this by:
Removing the source socket and letting the platform pick a random ephemeral one for you (as you have already found out).
Closing the connection at the server end first (so the CLOSE_WAIT ends up there). See server.close();
Resetting the client connection. See socket.resetAndDestroy()
Why are you specifying a local port in the first place? You almost never want to do that. If you don't, it'll work.
Any theory on why the socket is not available after the program exists is welcome!
The OS keeps the port in use for a while to be able to receive packets and tell the sender that the socket is gone.
Is there a way to properly destroy the socket so that it becomes immediately available again?
You can set the "linger" socket option to 0, so it'll become available immediately again, but again, you shouldn't get yourself in this situation in the first time. Consider whether you want to specify the local port. You usually don't.
is there a way to verify that the socket is "cooling down"
It'll be in the CLOSE_WAIT state.

Emit to all sockets on regular interval in socket io

I am wondering how I can send out a message to sockets on an interval, currently I am doing:
io.on('connection', function(socket){
setInterval(function () {
socket.emit('message', variable);
}, 100);
...
Each user then has an interval emitting messages every 100ms. Is there a better way of doing this?
I am also confused about how emit works: I was under the impression it sent the message to all sockets, but if I only start this interval for the first socket that connects and not the following sockets only the first socket receives the message?
Use io.emit to emit to all connected sockets. You can still do this in an interval as well.
// Only needed if you have to do something with a specific socket
io.on('connection', handleSocket);
setInterval(() => {
io.emit('message', variable);
}, 100);
just don`t forget to call clearInterval() finction when the socket connection is close.

Handle new TCP connections synchronously

I know nodejs is asynchronous by nature and it is preferable to use that way, but I have a use case where we need to handle incoming TCP connections in synchronous way. Once a new connections received we need to connect to some other TCP server and perform some book keeping stuff etc and then handle some other connection. Since number of connections are limited, it is fine to handle this in synchronous way.
Looking for an elegant way to handle this scenario.
net.createServer(function(sock) {
console.log('Received a connection - ');
var sock = null;
var testvar = null;
sock = new net.Socket();
sock.connect(PORT, HOST, function() {
console.log('Connected to server - ');
});
//Other listeners
}
In the above code if two connections received simultaneously the output may be (since asynchronous nature):
Received a connection
Receive a connection
Connected to server
Connected to server
But the expectation is:
Received a connection
Connected to server
Receive a connection
Connected to server
What is the proper way of ding this?
One solution is implement a queue kind of solution with emitting 'done' or 'complete' events to handle next connection.
For this we may have to take the connection callback out of the createServer call. How to handle scoping of connection and other variables (testvar) in this case?
In this case what happens to the data/messages if received on connections which are in queue but not yet processed and not yet 'data' listener is registered.?
Any other better solutions will be helpful.
I think it is important to separate the concepts of synchronous code vs serial code. You want to process each request serially, but that can still be accomplished while handling each request asynchronously. For your case, the easiest way would probably be to have a queue of requests to handle instead.
var inProgress = false;
var queue = [];
net.createServer(function(sock){
queue.push(sock);
processQueue();
});
function processQueue(){
if (inProgress || queue.length === 0) return;
inProgress = true;
handleSockSerial(queue.shift(), function(){
inProgress = false;
processQueue();
});
}
function handleSockSerial(sock, callback){
// Do all your stuff and then call 'callback' when you are done.
}
Note, as long as you are using node >= 0.10, the data coming in from the socket will be buffered until you read the data.

Node.js - tcp server close event handler is not working

Why is end event handler(socket) and close event handler(server) is being called at the same time?
I am expecting close event handler to be called after 30 seconds.
Can someone please help me?
Although after 30 seconds my TCP server is not accepting any new connection(keeps existing connections open) but I was expecting close event handler invocation after 30 sec.
close event handler of server as well as end event handler of socket is invoked when I forcefully close all existing tcp clients.
TCP connection ended
TCP connection ended
server closed but it will keep existing connection
var net = require("net");
function getSocketInfo(socketObject){
console.log('bytesRead= ' + socketObject.bytesRead);
console.log('bytesWritten= ' + socketObject.bytesWritten);
}
var tcpServer = net.createServer({allowHalfOpen:false},function(socketObject){
socketObject.setEncoding('utf8');
getSocketInfo(socketObject);
socketObject.on('data',function(data){
console.log('data received');
console.log(data);
console.log(data.length);
socketObject.write('Server Reply: ' + data,'utf8',function(){
console.log('data successfully written on socket');
});
getSocketInfo(socketObject);
});
socketObject.on('end',function(){
console.log('TCP connection ended');
});
});
setTimeout(function(){tcpServer.close();},30000);
tcpServer.on('close',function(){ console.log('server closed but it will keep existing connection');});
tcpServer.on('error',function(error){
console.log(error.code);
});
tcpServer.listen(8000,function(){
console.log('TCP server has been bound');
});
I got the answer after looking into the event section.
close handler will be called when ALL EXISTING TCP connections are closed, not immediately after close method invocation. This was strange but as per documentation it is correct behavior.
Event: 'close'#
Emitted when the server closes. Note that if connections exist, this
event is not emitted until all connections are ended.

NodeJS sockets initialized as unpaused?

A net.Socket object in NodeJS is a Readable Stream, however one note in the docs got me concerned:
For the Net.Socket 'data' event, the docs say
Note that the data will be lost if there is no listener when a Socket emits a 'data' event.
That seems to imply a Socket is returned to the calling script in "flowing-mode" and already un-paused? However, for a generic Readable Stream, the documentation for the 'data' event says
If you attach a data event listener, then it will switch the stream into flowing mode, and data will be passed to your handler as soon as it is available.
That "If" seems to imply if you wait a bit to bind to the 'data' event, the stream will wait for you, and if you intentionally want to miss the 'data' events, the example in the resume() method seems to indicate you must call the resume() method to start the flow of data.
My concern is that when working with a net.Server, when you receive a net.Socket as part of a 'connection' event, is it imperative that you start handling the 'data' events right away since it's already opened? Meaning if I do:
var s = new net.Server();
s.on('connection', function(socket) {
// Do some lengthy setup process here, blocking execution for a few seconds...
socket.on('data', function(d) { console.log(d); });
});
s.listen(8080);
Meaning not bind to the 'data' event right away, I could lose data? So is this a more robust way to handle incoming connections if you have a lengthy setup required for each one?
var s = new net.Server();
s.on('connection', function(socket) {
socket.pause(); // Not ready for you yet!
// Do some lengthy setup process here, blocking execution for a few seconds...
socket.on('data', function(d) { console.log(d); });
socket.resume(); // Okay, go!
});
s.listen(8080);
Anyone have experience working with listening on raw socket streams to know if this data loss is an issue?
I'm hoping this is an instance where the Net.Socket documentation wasn't updated since v0.10, since the stream documentation has a section that mentions 'data' events started emitting right away in versions prior to 0.10. Were TCP sockets properly updated to not start emitting 'data' packets right away, and the documentation not updated appropriately?
Yes, this is the docs flaw. Here is an example:
var net = require('net')
var server = net.createServer(onConnection)
function onConnection (socket) {
console.log('onConnection')
setTimeout(startReading, 1000)
function startReading () {
socket.on('data', read)
socket.on('end', stopReading)
}
function stopReading () {
socket.removeListener('data', read)
socket.removeListener('end', stopReading)
}
}
function read (data) {
console.log('Received: ' + data.toString('utf8'))
}
server.listen(1234, onListening)
function onListening () {
console.log('onListening')
net.connect(1234, onConnect)
}
function onConnect () {
console.log('onConnect')
this.write('1')
this.write('2')
this.write('3')
this.write('4')
this.write('5')
this.write('6')
}
All the data is received. If you explicitly resume() socket, you will lose it.
Also, if you do your "lengthy" setup in a blocking manner (which you shouldn't) you can't lose any IO as it has no chance to be processed, so no events will be emitted.

Resources