Search code examples
node.jssocketstcp

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!


Solution

  • 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()