Finding a Free Port in Java – 在Java中寻找一个自由端口

最后修改: 2020年 10月 16日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

When starting a socket server in our Java application, the java.net API requires us to specify a free port number to listen on. The port number is required so that the TCP layer can identify the application that the incoming data is intended for.

当在我们的Java应用程序中启动一个套接字服务器时,java.net API要求我们指定一个自由端口号来监听。端口号是必需的,这样TCP层才能识别传入的数据是为哪个应用程序准备的。

Specifying a port number explicitly is not always a good option, because applications might already occupy it. This will cause an input/output exception in our Java application.

明确指定一个端口号并不总是一个好的选择,因为应用程序可能已经占据了它。这将导致我们的Java应用程序出现输入/输出异常。

In this quick tutorial, we’ll look at how to check a specific port status and how to use an automatically allocated one. We’ll look into how this can be done with plain Java and Spring framework. We’ll also look at some other server implementations, like embedded Tomcat and Jetty.

在这个快速教程中,我们将看看如何检查特定的端口状态,以及如何使用自动分配的端口。我们将研究如何用普通的Java和Spring框架来完成这个任务。我们还将研究其他一些服务器的实现,如嵌入式Tomcat和Jetty。

2. Checking Port Status

2.检查端口状态

Let’s look at how we can check if a specific port is free or occupied using the java.net API.

让我们看看如何使用java.net API来检查一个特定的端口是否空闲或占用。

2.1. Specific Port

2.1.S特定端口

We’ll make use of the ServerSocket class from the java.net API to create a server socket, bound to the specified port. In its constructor, the ServerSocket accepts an explicit port number. The class also implements the Closeable interface, so it can be used in try-with-resources to automatically close the socket and free up the port:

我们将利用ServerSocket 类从java.net API中创建一个服务器套接字,绑定到指定的端口。在其构造函数中,ServerSocket接受一个明确的端口号。该类还实现了Closeable接口,因此它可以在try-with-resources中使用,以自动关闭套接字并释放端口:

try (ServerSocket serverSocket = new ServerSocket(FREE_PORT_NUMBER)) {
    assertThat(serverSocket).isNotNull();
    assertThat(serverSocket.getLocalPort()).isEqualTo(FREE_PORT_NUMBER);
} catch (IOException e) {
    fail("Port is not available");
}

In case we use a specific port twice, or it’s already occupied by another application, the ServerSocket constructor will throw an IOException:

如果我们两次使用一个特定的端口,或者它已经被其他应用程序占用,ServerSocket构造函数将抛出一个IOException

try (ServerSocket serverSocket = new ServerSocket(FREE_PORT_NUMBER)) {
    new ServerSocket(FREE_PORT_NUMBER);
    fail("Same port cannot be used twice");
} catch (IOException e) {
    assertThat(e).hasMessageContaining("Address already in use");
}

2.2. Port Range

2.2. plocation范围

Let’s now check how we can make use of the thrown IOException, to create a server socket using the first free port from a given range of port numbers:

现在让我们检查一下,我们如何利用抛出的IOException,从给定的端口号范围内使用第一个空闲端口创建一个服务器套接字。

for (int port : FREE_PORT_RANGE) {
    try (ServerSocket serverSocket = new ServerSocket(port)) {
        assertThat(serverSocket).isNotNull();
        assertThat(serverSocket.getLocalPort()).isEqualTo(port);
        return;
    } catch (IOException e) {
        assertThat(e).hasMessageContaining("Address already in use");
    }
}
fail("No free port in the range found");

3. Finding a Free Port

3.寻找一个空闲的端口

Using an explicit port number is not always a good option, so let’s look into possibilities to allocate a free port automatically.

使用一个明确的端口号并不总是一个好的选择,所以让我们看看自动分配一个空闲端口的可能性。

3.1. Plain Java

3.1.纯粹的Java

We can use a special port number zero in the ServerSocket class constructor. As a result, the java.net API will automatically allocate a free port for us:

我们可以在ServerSocket类构造函数中使用一个特殊的端口号0。结果,java.net API将自动为我们分配一个空闲的端口。

try (ServerSocket serverSocket = new ServerSocket(0)) {
    assertThat(serverSocket).isNotNull();
    assertThat(serverSocket.getLocalPort()).isGreaterThan(0);
} catch (IOException e) {
    fail("Port is not available");
}

3.2. Spring Framework

3.2.Spring框架

Spring framework contains a SocketUtils class that we can use to find an available free port. Its internal implementation uses the ServerSocket class, as shown in our previous examples:

Spring框架包含一个SocketUtils类,我们可以用它来寻找一个可用的空闲端口。它的内部实现使用了ServerSocket类,正如我们之前的例子中所示。

int port = SocketUtils.findAvailableTcpPort();
try (ServerSocket serverSocket = new ServerSocket(port)) {
    assertThat(serverSocket).isNotNull();
    assertThat(serverSocket.getLocalPort()).isEqualTo(port);
} catch (IOException e) {
    fail("Port is not available");
}

4. Other Server Implementations

4.其他服务器的实施

Let’s now take a look at some other popular server implementations.

现在让我们来看看其他一些流行的服务器实现。

4.1. Jetty

4.1. 喷气式码头

Jetty is a very popular embedded server for Java applications. It will automatically allocate a free port for us unless we set it explicitly via the setPort method of the ServerConnector class:

Jetty是一个非常流行的用于Java应用程序的嵌入式服务器它将自动为我们分配一个空闲端口,除非我们通过ServerConnector类的setPort方法明确设置它:

Server jettyServer = new Server();
ServerConnector serverConnector = new ServerConnector(jettyServer);
jettyServer.addConnector(serverConnector);
try {
    jettyServer.start();
    assertThat(serverConnector.getLocalPort()).isGreaterThan(0);
} catch (Exception e) {
    fail("Failed to start Jetty server");
} finally {
    jettyServer.stop();
    jettyServer.destroy();
}

4.2. Tomcat

4.2.汤姆猫

Tomcat, another popular Java embedded server, works a bit differently. We can specify an explicit port number via the setPort method of the Tomcat class. In case we provide a port number zero, Tomcat will automatically allocate a free port. However, if we don’t set any port number, Tomcat will use its default port 8080. Note that the default Tomcat port could be occupied by other applications:

Tomcat是另一个流行的Java嵌入式服务器,其工作方式有点不同。我们可以通过Tomcat类的setPort方法指定一个明确的端口号。如果我们提供的端口号为零,Tomcat将自动分配一个空闲的端口。然而,如果我们不设置任何端口号,Tomcat将使用其默认的8080端口。请注意,Tomcat的默认端口可能被其他应用程序占用。

Tomcat tomcatServer = new Tomcat();
tomcatServer.setPort(0);
try {
    tomcatServer.start();
    assertThat(tomcatServer.getConnector().getLocalPort()).isGreaterThan(0);
} catch (LifecycleException e) {
    fail("Failed to start Tomcat server");
} finally {
    tomcatServer.stop();
    tomcatServer.destroy();
}

5. Conclusion

5.总结

In this article, we explored how to check a specific port status. We also covered finding a free port from a range of port numbers and explained how to use an automatically allocated free port.

在这篇文章中,我们探讨了如何检查一个特定的端口状态。我们还介绍了从一系列端口号中找到一个空闲端口,并解释了如何使用自动分配的空闲端口。

In the examples, we covered the basic ServerSocket class from the java.net API and other popular server implementations, including Jetty and Tomcat.

在示例中,我们涵盖了来自java.net API的基本ServerSocket类和其他流行的服务器实现,包括Jetty和Tomcat。

As always, the complete source code is available over on GitHub.

一如既往,完整的源代码可在GitHub上获得