Java как проверить порт

Sockets: Discover port availability using Java

How do I programmatically determine the availability of a port in a given machine using Java? i.e given a port number, determine whether it is already being used or not?.

While this question is about how to know if a given port is already in use, you may have landed here trying to find a way to obtain a free port number, which stackoverflow.com/questions/2675362/… (with link to my gist.github.com/3429822) covers better.

For what purpose? If you just want to find a vacant socket to listen at, just specify zero. Any scanning technique is liable to timing-window problems: the port can be vacant when you scan and occupied when you go to claim in.

10 Answers 10

This is the implementation coming from the Apache camel project:

/** * Checks to see if a specific port is available. * * @param port the port to check for availability */ public static boolean available(int port) < if (port < MIN_PORT_NUMBER || port >MAX_PORT_NUMBER) < throw new IllegalArgumentException("Invalid start port: " + port); >ServerSocket ss = null; DatagramSocket ds = null; try < ss = new ServerSocket(port); ss.setReuseAddress(true); ds = new DatagramSocket(port); ds.setReuseAddress(true); return true; >catch (IOException e) < >finally < if (ds != null) < ds.close(); >if (ss != null) < try < ss.close(); >catch (IOException e) < /* should not be thrown */ >> > return false; > 

They are checking the DatagramSocket as well to check if the port is avaliable in UDP and TCP.

Читайте также:  Число степень двойки java

A nice variant of this if you have MINA is AvailablePortFinder.getNextAvailable(1024) which gets you the next non-privileged port.

This doesn’t catch everything however. I’ve been bitten by a running nginx on TCP 8000 whilst the above routine reports 8000 as available. No idea why — I suspect nginx does some sneaky stuff (this is on OS X). Workaround for me is to do the above and also to open a new Socket(«localhost», port) then return false if we don’t get an exception. Thoughts?

Same issue on Windows trying to detect if papercut SMTP server is running. A solution where you open a connection to a port, rather than trying to bind to a it (as suggested by Partly Clodys comment and Ivan’s answer) seems to work more reliable.

Interesting. The call to setReuseAddress() is completely pointless after the socket is already bound, and it it also completely contrary to the purpose of the code.

THis code is subject to timing-window problems. If the objective is to create a ServerSocket listening to some port, that’s what it should do, and return the ServerSocket . Creating it and then closing it and returning it provides zero guarantee that a subsequent ServerSocket can be created using that port. Ditto for DatagramSocket .

For Java 7 you can use try-with-resource for more compact code:

private static boolean available(int port) throws IllegalStateException < try (Socket ignored = new Socket("localhost", port)) < return false; >catch (ConnectException e) < return true; >catch (IOException e) < throw new IllegalStateException("Error while trying to check open port", e); >> 

This doesn’t test whether at port is available. It tests whether it is in LISTEN state, whether the IP address is reachable, etc.

@BaroudiSafwen It depends entirely on what the exception actually is. For ConnectException: ‘connection refused’ , yes it should return false. For timeouts, nothing it could return would be valid, as the actual answer isn’t known. That’s why this technique is useless for this purpose.

@BaroudiSafwen if the port you passed is being used, it will not throw an exception, returning false from the body of the try block. In contrast, if the port is not in use, it will throw an exception, in which case, you want the method to return true . However, as JMax commented, this test is slow.

It appears that as of Java 7, David Santamaria’s answer doesn’t work reliably any more. It looks like you can still reliably use a Socket to test the connection, however.

private static boolean available(int port) < System.out.println("--------------Testing port " + port); Socket s = null; try < s = new Socket("localhost", port); // If the code makes it this far without an exception it means // something is using the port and has responded. System.out.println("--------------Port " + port + " is not available"); return false; >catch (IOException e) < System.out.println("--------------Port " + port + " is available"); return true; >finally < if( s != null)< try < s.close(); >catch (IOException e) < throw new RuntimeException("You should handle this error." , e); >> > > 

if it is not available, then will it goes to finally statement ? because it’s already returned from your code.

If you’re not too concerned with performance, you could always try listening on a port using the ServerSocket class. If it throws an exception odds are it’s being used.

public static boolean isAvailable(int portNr) < boolean portFree; try (var ignored = new ServerSocket(portNr)) < portFree = true; >catch (IOException e) < portFree = false; >return portFree; > 

EDIT: If all you’re trying to do is select a free port then new ServerSocket(0) will find one for you.

Is there a way to do it without try/catch? I wouldn’t mind using any available port for my purposes, but iterating over port numbers and try/catch-ing over each one until I find a free one is a little wasteful. Isn’t there a ‘native boolean available(int)’ method somewhere, which just checks?

The following solution is inspired by the SocketUtils implementation of Spring-core (Apache license).

Compared to other solutions using Socket(. ) it is pretty fast (testing 1000 TCP ports in less than a second).

Of course it can only detect services that open a port on all interfaces or that explicitly run on localhost.

public static boolean isTcpPortAvailable(int port) < try (ServerSocket serverSocket = new ServerSocket()) < // setReuseAddress(false) is required only on macOS, // otherwise the code will not work correctly on that platform serverSocket.setReuseAddress(false); serverSocket.bind(new InetSocketAddress(InetAddress.getByName("localhost"), port), 1); return true; >catch (Exception ex) < return false; >> 

A cleanup of the answer pointed out by David Santamaria:

/** * Check to see if a port is available. * * @param port * the port to check for availability. */ public static boolean isPortAvailable(int port) < try (var ss = new ServerSocket(port); var ds = new DatagramSocket(port)) < return true; >catch (IOException e) < return false; >> 

This is still subject to a race condition pointed out by user207421 in the comments to David Santamaria’s answer (something could grab the port after this method closes the ServerSocket and DatagramSocket and returns).

The try/catch socket based solutions , might not yield accurate results (the socket address is «localhost» and in some cases the port could be «occupied» not by the loopback interface and at least on Windows I’ve seen this test fails i.e. the prot falsely declared as available).

There is a cool library named SIGAR , the following code can hook you up :

Sigar sigar = new Sigar(); int flags = NetFlags.CONN_TCP | NetFlags.CONN_SERVER | NetFlags.CONN_CLIENT; NetConnection[] netConnectionList = sigar.getNetConnectionList(flags); for (NetConnection netConnection : netConnectionList) < if ( netConnection.getLocalPort() == port ) return false; >return true; 

Источник

Test if remote port is in use

I have the need to discover open ports on a remote server. I’m wondering if this is possible. I was thinking I’d open a socket, and if this succeeds, it means that it’s used . otherwise, if I get an exception, then it is not used. For example,

public boolean isActive() < Socket s = null; try < s = new Socket(); s.setReuseAddress(true); SocketAddress sa = new InetSocketAddress(this.host, this.port); s.connect(sa, 3000); return true; >catch (IOException e) < e.printStackTrace(); >finally < if (s != null) < try < s.close(); >catch (IOException e) < >> > return false; > 

@Hector The answers on that question are mostly about testing whether something is bound to a port locally. This question is about a remote system.

2 Answers 2

FWIW, a Java solution I use from times to times (better than telnet: supports timeout).

package com.acme.util; import java.io.IOException; import java.net.InetSocketAddress; import java.net.Socket; import java.net.SocketAddress; import java.net.SocketTimeoutException; import java.net.UnknownHostException; public class CheckSocket < public static void main(String[] args) < int exitStatus = 1 ; if (args.length != 3) < System.out.println("Usage: CheckSocket node port timeout"); >else < String node = args[0]; int port = Integer.parseInt(args[1]); int timeout = Integer.parseInt(args[2]); Socket s = null; String reason = null ; try < s = new Socket(); s.setReuseAddress(true); SocketAddress sa = new InetSocketAddress(node, port); s.connect(sa, timeout * 1000); >catch (IOException e) < if ( e.getMessage().equals("Connection refused")) < reason = "port " + port + " on " + node + " is closed."; >; if ( e instanceof UnknownHostException ) < reason = "node " + node + " is unresolved."; >if ( e instanceof SocketTimeoutException ) < reason = "timeout while attempting to reach node " + node + " on port " + port; >> finally < if (s != null) < if ( s.isConnected()) < System.out.println("Port " + port + " on " + node + " is reachable!"); exitStatus = 0; >else < System.out.println("Port " + port + " on " + node + " is not reachable; reason: " + reason ); >try < s.close(); >catch (IOException e) < >> > > System.exit(exitStatus); > > 

Источник

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

При запуске сокет-сервера в нашем 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 .

Источник

Оцените статью