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

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


当前回答

这里有很多使用ServerSocket的答案。我检查了Micronauts实现,他们转而尝试将客户端套接字连接到本地端口,如果失败,他们说端口是开放的。对我来说,这样做的好处是他们不必冒险在测试中使用端口。

它们的代码是这样的:

    public static boolean isTcpPortAvailable(int currentPort) {
        try (Socket socket = new Socket()) {
            socket.connect(new InetSocketAddress(InetAddress.getLocalHost(), currentPort), 20);
            return false;
        } catch (Throwable e) {
            return true;
        }
    }

参考网址:https://github.com/micronaut-projects/micronaut-core/blob/3.4.x/core/src/main/java/io/micronaut/core/io/socket/SocketUtils.java

其他回答

如果不介意使用的端口,可以向ServerSocket构造函数指定一个端口0,它将侦听任何空闲端口。

ServerSocket s = new ServerSocket(0);
System.out.println("listening on port: " + s.getLocalPort());

如果您希望使用一组特定的端口,那么最简单的方法可能是遍历它们,直到其中一个可以工作为止。就像这样:

public ServerSocket create(int[] ports) throws IOException {
    for (int port : ports) {
        try {
            return new ServerSocket(port);
        } catch (IOException ex) {
            continue; // try next port
        }
    }

    // if the program gets here, no port in the range was found
    throw new IOException("no free port found");
}

可以这样使用:

try {
    ServerSocket s = create(new int[] { 3843, 4584, 4843 });
    System.out.println("listening on port: " + s.getLocalPort());
} catch (IOException ex) {
    System.err.println("no available ports");
}

这可能对你没有太大帮助,但在我的(Ubuntu)机器上,我有一个文件/etc/services,其中至少给出了一些应用程序使用/保留的端口。这些是这些应用的标准端口。

不能保证这些端口正在运行,只是这些应用程序使用的默认端口(所以如果可能的话,你不应该使用它们)。

定义了500多个端口,大约一半是UDP,一半是TCP。

这些文件是使用IANA的信息制作的,请参见IANA指定的端口号。

欧洲经济区ServerSocket:

创建绑定到指定端口的服务器套接字。端口为0在任何空闲端口上创建套接字。

根据维基百科,如果你不需要一个“众所周知”的端口,你应该使用端口49152到65535。

判断一个端口是否正在使用的唯一方法是尝试打开它。

如果你想使用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();