Перейти к основному содержимому

Поиск свободного порта в Java

· 4 мин. чтения

1. Обзор

При запуске сокет-сервера в нашем Java-приложении API java.net требует, чтобы мы указали свободный номер порта для прослушивания. Номер порта требуется, чтобы уровень TCP мог идентифицировать приложение, для которого предназначены входящие данные.

Явное указание номера порта не всегда является хорошим вариантом, так как приложения могут уже занимать его. Это вызовет исключение ввода/вывода в нашем Java-приложении.

В этом кратком руководстве мы рассмотрим, как проверить состояние определенного порта и как использовать автоматически выделенный порт. Мы рассмотрим, как это можно сделать с помощью простой среды Java и Spring. Мы также рассмотрим некоторые другие реализации серверов, такие как встроенные Tomcat и Jetty.

2. Проверка состояния порта

Давайте посмотрим, как мы можем проверить, свободен или занят конкретный порт, используя API java.net .

2.1. Специальный порт

Мы будем использовать класс ServerSocket из API java.net для создания серверного сокета, привязанного к указанному порту. В своем конструкторе 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");
}

Если мы используем определенный порт дважды или он уже занят другим приложением, конструктор 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. Диапазон портов _

Давайте теперь проверим, как мы можем использовать выброшенное исключение 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. Поиск свободного порта

Использование явного номера порта не всегда является хорошим вариантом, поэтому давайте рассмотрим возможности автоматического выделения свободного порта.

3.1. Обычная Java

Мы можем использовать специальный нулевой номер порта в конструкторе класса ServerSocket . В результате API java.net автоматически выделит нам свободный порт:

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 содержит класс 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. Другие реализации сервера

Давайте теперь взглянем на некоторые другие популярные реализации сервера.

4.1. пристань

Jetty — очень популярный встроенный сервер для Java-приложений. Он автоматически выделит нам свободный порт, если мы не установим его явно с помощью метода setPort класса ServerConnector :

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 , другой популярный встроенный сервер Java, работает немного по-другому. Мы можем указать явный номер порта с помощью метода setPort класса Tomcat . Если мы укажем нулевой номер порта, 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. Вывод

В этой статье мы рассмотрели, как проверить состояние определенного порта. Мы также рассмотрели поиск свободного порта из диапазона номеров портов и объяснили, как использовать автоматически выделенный свободный порт.

В примерах мы рассмотрели базовый класс ServerSocket из API java.net и других популярных реализаций сервера, включая Jetty и Tomcat.

Как всегда, полный исходный код доступен на GitHub .