13

With Node.js, we can create a server and listen on a random port:

var server = net.createServer();
server.listen(0, '127.0.0.1');

The first parameter, port 0, indicates choose a random port, and 127.0.0.1 indicates to listen on localhost only, as documented.

Does Node.js select a port that isn't in use? Do I have to check that myself and retry if Node.js happens to pick a port that is already open and bound to another application? Does it pick any old port, or only userland ports (>1024)?

Brad
  • 146,404
  • 44
  • 300
  • 476
  • I think it simply assigns a random port but I'm not 100%. I think you need to do the on error and increment etc... like in the link (they retry with the same port though) – bryanmac Mar 28 '12 at 05:18
  • But then you have to wonder what it means to start up on some random available port - unless you have some sort of service discovery, it's hard for others and client to discover what you randomly found :) – bryanmac Mar 28 '12 at 05:20
  • That's not usually a problem as you'd agree on a port or use a well-known-port. If you don't have permission to bind said port, then you have other issues to solve. – David-SkyMesh Mar 28 '12 at 08:41
  • @bryanmac, I have specific reasons for binding to a random port. See http://stackoverflow.com/questions/9881305/overriding-node-js-http-parser Once bound, I can call `server.address()` easily enough to get the port that I'm on. – Brad Mar 28 '12 at 14:00

2 Answers2

27

The OS assigns the port number. See https://github.com/joyent/node/blob/v0.6.11/lib/net.js#L780-783

On OS X, the assignment is sequential, userland and does not check the port to verify it is not in use.

On Ubuntu 11.04, the assignment is random, userland and also does not check if port is in use.

The script below can be used to test on other platforms. To verify the ports are userland, I ran the script 10,000 times via bash piped to grep -c "port: [0-9]{1,3}" with zero matches.

var net = require('net'),
    firstPort;

(function createServer(port) {
  var server = net.createServer();
  server.listen(port, function() {
    address = server.address();
    if (port === 0) { 
      if (firstPort === undefined) {
        firstPort = address.port;
        // cause a EADDRINUSE in 10 more sockets for sequential platforms
        // without this, will run out of fd's before hitting EADDRINUSE
        createServer(firstPort + 10); 
        console.log('addr in use port trap: ', firstPort + 10);
      } else {
        // on OS X (sequential) this will increment the OS's sequential counter
        // and not cause EADDRINUSE
        createServer(address.port + 1);
      }
      createServer(0);
    }
    console.log("requested port:", port, " binded port:",address.port);
  });  
})(0);
Krut
  • 3,752
  • 2
  • 30
  • 41
  • The operating system does indeed skip the port if it is in use. There is a bug in your code. The collision is happening at `createServer(address.port + 1)` and not in `createServer(0)`. – Trott Jan 14 '19 at 04:21
  • 2
    Here is code demonstrating that it skips an occupied port on macOS: https://gist.github.com/Trott/4caed3e2ce93a92318ec1d54aedbbc80 – Trott Jan 14 '19 at 04:30
7

Does Node.js select a port that isn't in use?

Yes, the port will be an available port. The operating system selects a port that isn't in use rather than Node.js, but from the end-user perspective, that's more-or-less the same thing.

The documentation no doubt had different wording at the time this question was originally posted in 2012, but as of now (January 2019), it is explicit about this: "If port is omitted or is 0, the operating system will assign an arbitrary unused port...".

Do I have to check that myself and retry if Node.js happens to pick a port that is already open and bound to another application?

No, you do not. You should handle errors anyway as any number of things can go wrong. But writing extra code to test for port availability is not something you need to do.

Does it pick any old port, or only userland ports (>1024)?

As far as I know, it will always be an unprivileged port.


For operating systems like macOS that assign available ports sequentially, here is code that shows that the operating system will skip a port if it is unavailable.

// Testing for macOS, which supplies available ports sequentially.

var net = require('net');

createServer(0, function () {
  var port = this.address().port;
  console.log('server was assigned port ' + port);
  createServer(port+1, function () {
    var port = this.address().port;
    console.log('server was assigned port ' + port);
    createServer(0, function () {
      var port = this.address().port;
      // This line will show that the OS skipped the occupied port and assigned the next available port.
      console.log('server was assigned port ' + port);
    });
  });
});

function createServer(port, callback) {
  console.log('create server with port ' + port);
  var server = net.createServer();
  server.listen(port, callback).unref();
}
Trott
  • 52,114
  • 21
  • 134
  • 179