1. Обзор
При запуске сервера сокетов в нашем Java-приложении java.net API требует, чтобы мы указали номер свободного порта для прослушивания. Номер порта необходим для того, чтобы уровень TCP мог идентифицировать приложение, для которого предназначены входящие данные.
Явное указание номера порта не всегда является хорошим вариантом, поскольку приложения могут уже занимать его. Это вызовет исключение ввода/вывода в нашем Java-приложении.
В этом кратком руководстве мы рассмотрим, как проверить состояние конкретного порта и как использовать автоматически выделенный порт. Мы рассмотрим, как это можно сделать с помощью простой Java и Spring framework. Мы также рассмотрим некоторые другие реализации серверов, такие как embedded Tomcat и Jetty.
2. Проверка Состояния Порта
Давайте посмотрим, как мы можем проверить, свободен ли конкретный порт или занят, используя java.net API.
2.1. Конкретный порт
Мы будем использовать класс ServerSocket из java.net API для создания serversocket, привязанного к указанному порту. В своем конструкторе , 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, для создания serversocket с использованием первого свободного порта из заданного диапазона номеров портов:
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 . В результате 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 содержит класс Socket Utils , который мы можем использовать для поиска доступного свободного порта. Его внутренняя реализация использует класс 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 из java.net API и другие популярные серверные реализации, включая Jetty и Tomcat.
Как всегда, полный исходный код доступен на GitHub .