Node.js如何选择随机端口?

14

使用Node.js,我们可以创建一个服务器并侦听随机端口:

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

第一个参数,端口0,表示选择一个随机端口,127.0.0.1表示仅监听本地主机,正如文档中所述

Node.js会选择一个未被使用的端口吗?我需要自己检查并重试吗,如果Node.js恰好选取了已经打开并绑定到另一个应用程序的端口?它会选择任何旧端口,还是只有用户区端口(>1024)?


我认为它只是分配一个随机端口,但我不确定。我认为您需要像链接中一样执行on error和increment等操作(但他们会重试相同的端口)。 - bryanmac
但是你必须想知道,在某个随机可用的端口上启动意味着什么 - 除非你有某种服务发现,否则其他人和客户端很难发现你随机找到了什么 :) - bryanmac
通常这不是问题,因为你可以协商一个端口或使用一个众所周知的端口。如果你没有权限绑定该端口,那么你就有其他问题需要解决。 - David-SkyMesh
@bryanmac,我绑定到随机端口有特定的原因。请参见https://dev59.com/0GHVa4cB1Zd3GeqPsPyB。一旦绑定,我可以轻松调用`server.address()`来获取所在的端口。 - Brad
2个回答

28
操作系统会分配端口号。详情请参见https://github.com/joyent/node/blob/v0.6.11/lib/net.js#L780-783
在OS X上,分配是顺序的,由用户空间完成,并且不检查端口以验证其未被使用。
在Ubuntu 11.04上,分配是随机的,由用户空间完成,并且同样不检查端口是否已被使用。
以下脚本可用于在其他平台上进行测试。为了验证端口是用户空间的,我通过bash运行了脚本10,000次并将其管道传递到grep -c "port: [0-9]{1,3}"以查找零个匹配项。
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);

操作系统确实会跳过已被使用的端口。你的代码存在一个错误。冲突发生在 createServer(address.port + 1) 而不是 createServer(0) - Trott
2
以下是代码示例,演示了如何跳过 macOS 上的占用端口:https://gist.github.com/Trott/4caed3e2ce93a92318ec1d54aedbbc80 - Trott

9

Node.js会选择一个未被使用的端口吗?

是的,端口将是可用的端口。操作系统会选择一个未被使用的端口,而不是Node.js,但从最终用户的角度来看,这差不多是一样的。

毫无疑问,文档在此问题最初发布于2012年时可能有不同的措辞,但截至目前(2019年1月),它明确说明了这一点:“如果省略端口或端口为0,则操作系统将分配任意未使用的端口...”。

我需要自己检查并重试吗,如果Node.js恰好选择了已经打开并绑定到另一个应用程序的端口?

不需要,你不需要编写额外的代码来测试端口的可用性。

它选择任何旧端口,还是只选择用户区域端口(>1024)?

据我所知,它总是选择未特权端口。


对于像 macOS 这样按顺序分配可用端口的操作系统,以下代码显示如果端口不可用,则操作系统将跳过该端口。

// 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();
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接