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