我想启动一个侦听端口的服务器。我可以显式地指定端口,它工作。但我想以自动的方式找到一个端口。在这方面,我有两个问题。

我应该在哪个范围内搜索端口号?(我使用的端口是12345、12346和12347,没有问题)。 我如何知道给定的端口是否被其他软件占用?


当前回答

从Java 1.7开始,你可以像这样使用try-with-resources:

  private Integer findRandomOpenPortOnAllLocalInterfaces() throws IOException {
    try (
        ServerSocket socket = new ServerSocket(0);
    ) {
      return socket.getLocalPort();

    }
  }

如果需要在特定接口上找到一个开放端口,请检查ServerSocket文档以获得替代构造函数。

警告:任何使用此方法返回的端口号的代码都会受到竞态条件的影响——在关闭ServerSocket实例后,不同的进程/线程可能会立即绑定到相同的端口。

其他回答

如果您将0作为端口号传递给ServerSocket的构造函数,它将为您分配一个端口。

如果你想使用ServerSocket创建你自己的服务器,你可以让它为你选择一个空闲端口:

  ServerSocket serverSocket = new ServerSocket(0);
  int port = serverSocket.getLocalPort();

其他服务器实现通常也有类似的支持。例如,Jetty选择一个空闲端口,除非你显式地设置它:

  Server server = new Server();
  ServerConnector connector = new ServerConnector(server);
  // don't call: connector.setPort(port);
  server.addConnector(connector);
  server.start();
  int port = connector.getLocalPort();

你可以让ServerSocket为你找到一个端口,然后关闭它:

private int getFreePort() {
        var freePort = 0;
        try (ServerSocket s = new ServerSocket(0)) {
            freePort = s.getLocalPort();
        } catch (Exception e) {
            e.printStackTrace();
        }

        return freePort;
    }

如果你正在使用Spring框架,最直接的方法是:

private Integer laancNotifyPort = SocketUtils.findAvailableTcpPort();

你也可以设置一个可接受的范围,它会在这个范围内搜索:

private Integer laancNotifyPort = SocketUtils.findAvailableTcpPort(9090, 10090);

这是一种方便的方法,它抽象了复杂性,但在内部与本线程中的许多其他答案相似。

Eclipse SDK包含一个SocketUtil类,它可以做你想做的事情。你可以看看git的源代码。