Nodejs 随机免费 tcp 端口

Nodejs random free tcp ports

每次实例化我的 class 的新实例时,我的项目都需要设置一个新端口。

在 Node.js 中,我如何找到空闲的 TCP 端口来设置我的新套接字服务器?或者检查我指定的端口是否已经被使用。

要找到一个开放的 TCP 端口,您可以使用模块 portastic

您可以找到这样的端口:

port = require('portastic');

options = {
    min : 8000,
    max : 8005
}

port.find(options, function(err, data){
    if(err)
        throw err;
    console.log(data);
});

您可以通过为端口指定 0 来绑定到 OS 分配的随机空闲端口。这样你就不会受到竞争条件的影响(例如,在你有机会绑定到它之前检查一个开放的端口和一些绑定到它的进程)。

然后你可以调用server.address().port.

获取分配的端口

示例:

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

对于 Express 应用:

const app = require('express')();

const server = app.listen(0, () => {
  console.log('Listening on port:', server.address().port);
});

等待港口

对于那些尝试“同步”执行此操作的人,下游代码取决于 OS 选择的 port 例如,在创建测试服务器时并将端口传递给测试 ),以下方法对我很有帮助:

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

如果 运行 针对实时服务器进行集成测试,这允许我们 await 端口号变得可用,并且 return 这样我们的 testClient 可以命中 localhost 在这个端口上!

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

在本地构建 运行 应用程序时,我曾多次使用公认的答案 - 感谢@mscdex。但是,我最近有一个用例,如果可能的话,最好坚持使用给定的端口,但如果使用了另一个端口,仍然会回退到另一个端口。

这样做的原因是我想使用 localStorage 保存应用程序首选项,为了安全起见,它仅限于同一站点,具有相同的端口。因此,我希望尽可能始终使用端口 3000,但如果需要,则回退到 3001 或 3002 等,直到一个可用为止。如果正在使用的端口不是 3000,那么我将回退到存储在用户硬盘上的应用程序首选项的副本。

我用这个模式来做这个:

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() 只是一个将浏览器启动到 'http://127.0.0.1:' + server.address().port

的函数

该应用程序是一个简单的本地服务器 + 浏览器应用程序。浏览器是 GUI,服务器在用户硬盘上修改文件等。

端口查找器库:

https://github.com/http-party/node-portfinder

我建议你使用 portfinder 库,它在一周内有超过 1000 万的下载量。

默认情况下 portfinder 库将从 8000 开始搜索并扫描直到达到最大端口号 (65535)。

const portfinder = require('portfinder');

portfinder.getPort((err, port) => {
    //
    // `port` is guaranteed to be a free port
    // in this scope.
    //
});

我使用这个紧凑的形式:

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

使用:

const PORT = await getPortFree()