Nodejs random free tcp ports
node.jsTcpPortnode.js Problem Overview
My project need to setup a new port every time a new instance of my class is instantiated.
In Node.js how I can find a free TCP port to set in my new socket server? Or check if my specified port is already used or not.
node.js Solutions
Solution 1 - node.js
You can bind to a random, free port assigned by the OS by specifying 0
for the port. This way you are not subject to race conditions (e.g. checking for an open port and some process binding to it before you get a chance to bind to it).
Then you can get the assigned port by calling server.address().port
.
Example:
var net = require('net');
var srv = net.createServer(function(sock) {
sock.end('Hello world\n');
});
srv.listen(0, function() {
console.log('Listening on port ' + srv.address().port);
});
Solution 2 - node.js
For Express app:
const app = require('express')();
const server = app.listen(0, () => {
console.log('Listening on port:', server.address().port);
});
Solution 3 - node.js
To find an opened TCP's port you can use the module portastic
You can find a port like this:
port = require('portastic');
options = {
min : 8000,
max : 8005
}
port.find(options, function(err, data){
if(err)
throw err;
console.log(data);
});
Solution 4 - node.js
Port Finder Library:
https://github.com/http-party/node-portfinder
I suggest you use portfinder
library, it has over 10 million downloads in a week.
By default portfinder
library will start searching from 8000 and scan until the maximum port number (65535) is reached.
const portfinder = require('portfinder');
portfinder.getPort((err, port) => {
//
// `port` is guaranteed to be a free port
// in this scope.
//
});
Solution 5 - node.js
I use this compact form:
import net from "net"
async function getPortFree() {
return new Promise( res => {
const srv = net.createServer();
srv.listen(0, () => {
const port = srv.address().port
srv.close((err) => res(port))
});
})
}
use:
const PORT = await getPortFree()
Solution 6 - node.js
Await'ing the port
For those of you trying to do this "synchronously", with downstream code dependent on the port
that is chosen by the OS (e.g. while creating a test server and passing the port to tests), the following recipe has served me well:
export const sleepForPort = async (httpServer: Server, ms: number): Promise<number> => {
return new Promise<number>((resolve, reject) => {
httpServer.listen(0, async () => {
try{
let addr = (httpServer.address() as AddressInfo | null)
while(! (addr && addr.port) ) {
await sleep(ms);
addr = httpServer.address() as AddressInfo | null
}
resolve(addr.port);
}catch(e){
reject(e);
}
});
});
}
const sleep = (ms: number) => {
return new Promise(resolve => setTimeout(resolve, ms));
}
If running integration tests against a live server, this allows us to await
the port number becoming available, and return this so our testClient
can hit localhost
on this port!
export const setupTests = async () => {
const app = createExpressApp(...);
const httpServer = createServer(app);
server.installSubscriptionHandlers(httpServer); // Testing graphql subscriptions
const port = await sleepForPort(httpServer, 100);
return {port}
}
describe("Http server test", () => {
let port: number;
beforeAll(async () => {
{port} = await setupTests()
})
it("Hits the right port", () => {
const res = await fetch(`http://localhost:${port}/testing`)
expect(res).toBeDefined()
expect(res.status).toEqual(200);
}
})
Solution 7 - node.js
I've used the accepted answer on numerous occasions when building apps that run locally - thanks @mscdex. However, I had a use case recently when it would be preferable to stick to a given port if possible, but still to fallback to another port if that one is taken.
The reason for this is I wanted to save app preferences using localStorage, which is restricted to the same site, with the same port for security. Therefore, I wanted to always use port 3000 when possible, but if needed fallback to 3001, or 3002, etc. until one is available. If the port being used is not 3000, then I fallback to a copy of the app preferences stored on the user's hard disk.
I do this with this pattern:
const http = require('http');
const server = http.createServer(function(req,res){ ... })
const config = {
port: 3000,
launched: false,
};
serverListen(server, config.port);
function serverListen(server, port){
server.on('error', e => {
console.log(`port ${config.port} is taken`)
config.port +=1;
server.close();
serverListen(server, config.port);
}).listen(port, function() {
if (config.launched){
return;
}
console.log('Listening on port ' + server.address().port);
launchBrowser();
config.launched = true;
});
}
launchBrowser()
is just a function that launches the browser to 'http://127.0.0.1:' + server.address().port
The app is a simple local server + browser app. With the browser being the GUI and the server doing the modification of files etc. on the user's harddrive.