Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Node.js: client doesn't die when TCP connection closes

I built a simple TCP server and a simple TCP client in Node.js

Now, when the client sends "exit" to the server, the connection is successfully closed. The server deletes the socket from its sockets list and sends "Bye bye!" to the client.

The connection on the client is closed as well but the app is still waiting for other inputs, so it doesn't die and I'm forced to type CTRL+C.

I tried adding process.exit() after connection closes but it doesn't work:

CLIENT CODE:

var net = require('net'),
    config = require(__dirname + '/config.json'),
    connection = net.createConnection(config.port, config.host);

connection.setEncoding('utf8');

connection.on('connect', function () {
    console.log('Connected');
});

connection.on('error', function (err) {
    console.error(err);
});

connection.on('data', function (data) {
    console.log('» ' + data);
});

connection.on('close', function() {
    console.log('Connection closed');
});

process.stdin.on('data', function (data) {

    if ((new String(data)).toLowerCase() === 'exit') {
        connection.end();
        process.exit();
    }
    else {
        connection.write(data);
    }

});

process.stdin.resume();

SERVER CODE:

var server = require('net').createServer(),
    config = require(__dirname + '/config.json'),
    sockets = [];

server.on('connection', function (socket) {
    socket.setEncoding('UTF-8');

    socket.on('data', function (data) {

        console.log('Received data: ' + data);

        if (data.trim().toLowerCase() === 'exit') {
            socket.write("Bye bye!\n");
            socket.end();
        }
        else {
            sockets.forEach(function (client) {
                if (client && client != socket) {
                    client.write(data);
                }
            });
        }

    });

    socket.on('close', function () {
        console.log('Connection closed');
        sockets.splice(sockets.indexOf(socket), 1);

        console.info('Sockets connected: ' + sockets.length);
    });

    sockets.push(socket);
});

server.on('listening', function () {
    console.log('Server listening');
});

server.on('close', function () {
    console.log('Server is now closed');
});

server.on('error', function (err) {
    console.log('error:', err);
});

server.listen(config.port);

EDIT:

I added a client connection "on close" event handler. So, the string "Connection closed" is now printed by the server and by the client too.

like image 275
Francesco Casula Avatar asked Oct 24 '12 12:10

Francesco Casula


People also ask

What happens when a TCP connection is closed?

The TCP session is sending packets as fast as possible, so when the client sends the FIN and closes its part, the server is still sending lots of data for a moment. In this case, the client sends RST packets until the server stops sending data.

How long you can keep a TCP connection alive?

Description. Once a TCP connection has been established, that connection is defined to be valid until one side closes it. Once the connection has entered the connected state, it will remain connected indefinitely.

How do I know if my TCP connection is closed?

Enter "telnet + IP address or hostname + port number" (e.g., telnet www.example.com 1723 or telnet 10.17. xxx. xxx 5000) to run the telnet command in Command Prompt and test the TCP port status. If the port is open, only a cursor will show.


2 Answers

I think you're looking for this: socket.unref().

From Node.js documentation (https://nodejs.org/api/net.html#net_socket_unref):

socket.unref()#

Calling unref on a socket will allow the program to exit if this is the only active socket in the event system. If the socket is already unrefd calling unref again will have no effect.

like image 92
hoang21 Avatar answered Oct 13 '22 01:10

hoang21


Some time ago when improving the tests suite for node-cubrid module, I had encountered the same problem. After all tests have passed, nodeunit process didn't quit because node-cubrid was using connection.end() to close the client socket when timeout occurs, just like you did.

Then I replaced connection.end() with connection.destroy(), a cleaner way to ensure the socket is really closed without actually terminating the running process, which, I think, is a better solution than the above suggested process.exit(). So, in your client code context, I would do:

process.stdin.on('data', function (data) {
    if ((new String(data)).toLowerCase() === 'exit') {
       connection.destroy();
    }
    else {
       connection.write(data);
    }
});

According to Node.js documentation:

socket.destroy()

Ensures that no more I/O activity happens on this socket. Only necessary in case of errors (parse error or so).

like image 43
Eye Avatar answered Oct 13 '22 00:10

Eye