12

Background

I am communicating with a machine using net.Socket via TCP/IP.

I am able to establish the connection and to send and receive packets of Buffers, which is all fine.

Problem

The problem is that if I manually disconnect the internet cable from the machine, my Node.js connection doesn't fire the close event and I have no means to know if something failed!

Code

let socket;

const start = async function ( config ) {

    await connecToBarrier( config )
        .then( () => console.log( "connected to barrrier" ) )
        .catch( err => {
            throw new Error( `Cannot connect to barrier: ${err}` );
        } );
};

const connecToBarrier = function ( connectOpts ) {
    return new Promise( ( resolve, reject ) => {
        //connectOpts is an object with 'port' and 'host'
        socket = net.createConnection( connectOpts, () => {
            //once I receive a 'hello world' from the machine, I can continue
            socket.once( "data", () => resolve() );
        } );

        socket.on( "connection", () => {
            console.log("onConnection says we have someone!");
        } );

        socket.on( "error", err => {
            console.log(`onError says: ${err}`);
            reject(err);
        } );

        socket.on( "timeout", () => {
            console.log("onTimeout says nothing");
            reject();
        } );

        socket.on( "end", () => {
            console.log("onEnd says nothing");
            reject();
        } );

        socket.on( "close", err => {
            console.log(`onClose says: ${err}`);
            reject(err);
        } );
    } );
};


start();

Research

@robertklep mentioned the setKeepAlive option, however according to

How to test socket.setKeepAlive in NodeJS

it doesn't work. A more profound research shows that this is highly dependant on the Operative System you are using, as per https://stackoverflow.com/a/18678494/1337392

So in other words, unless I am willing to wait several minutes for my heartbeats to actually do something, I don't see a way out of this.

Question

How do I detect if a connection died?

0

2 Answers 2

10

Here's an interesting read: https://blog.stephencleary.com/2009/05/detection-of-half-open-dropped.html

Note in particular this remark:

It is important to note that the act of receiving data is completely passive in TCP; a socket that only reads cannot detect a dropped connection.

This is exactly what's happening in your case: your socket is waiting for new data to arrive, which never happens. Some OS'es, in particular of the UNIX type, may wait a very long time before they start invalidating open connections if a network interface went down.

The article also proposes a solution that may work on Node.js: enabling TCP Keepalive. This will periodically send packets to the peer to check if the connection is still working.

To enable this on your sockets:

socket.setKeepalive(true, 5000);

This will start checking the connection 5 seconds after it has received the last packet. More info here: https://nodejs.org/api/net.html#net_socket_setkeepalive_enable_initialdelay

Sign up to request clarification or add additional context in comments.

4 Comments

What what happens if the connection falls meanwhile? Which net.Socket even will be triggered?
According to the above code, no event is ever fired !
it appears setKeepAlive is not reliable in Node.js stackoverflow.com/questions/20561596/… ... great, just what I needed. Nice try though, kudos++ for help! Also, it is nice to see you again :D
Well, it depends on your OS settings at which point it will consider the connection to be dead. For Linux, it may still take 11 minutes before it will stop sending keep-alives and declare the connection to be dead. You can decrease that time, though: tldp.org/HOWTO/TCP-Keepalive-HOWTO/usingkeepalive.html What setKeepAlive does is decrease the default "wait period" after which the kernel starts sending the keep-alive packets (which on Linux is 2 hours...)
5

I had the same issue. I ended up doing this as a fix:

const _connect = () => {
  const socket = new net.Socket();
    socket.connect(this.port, this.host);
    socket.setTimeout(10000);

    socket.on('timeout', () => {
        socket.destroy();
        _connect(); 
    });
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.