Trovare una porta libera in Java

1. Panoramica

Quando si avvia un server socket nella nostra applicazione Java, l' API java.net ci richiede di specificare un numero di porta libero su cui ascoltare. Il numero di porta è necessario affinché il livello TCP possa identificare l'applicazione a cui sono destinati i dati in entrata.

Specificare un numero di porta in modo esplicito non è sempre una buona opzione, perché le applicazioni potrebbero già occuparlo. Ciò causerà un'eccezione di input / output nella nostra applicazione Java.

In questo breve tutorial vedremo come controllare lo stato di una porta specifica e come utilizzarne una assegnata automaticamente. Vedremo come farlo con il semplice framework Java e Spring. Esamineremo anche alcune altre implementazioni di server, come Tomcat e Jetty incorporati.

2. Verifica dello stato della porta

Diamo un'occhiata a come possiamo verificare se una porta specifica è libera o occupata utilizzando l' API java.net .

2.1. S pecifici Port

Faremo uso della classe ServerSocket dall'API java.net per creare un socket del server, associato alla porta specificata. Nel suo costruttore , ServerSocket accetta un numero di porta esplicito. La classe implementa anche l' interfaccia Closeable , quindi può essere utilizzata in try-with-resources per chiudere automaticamente il socket e liberare la porta:

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"); }

Nel caso in cui utilizziamo una porta specifica due volte, o è già occupata da un'altra applicazione, il costruttore ServerSocket lancerà una 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. P ort Gamma

Controlliamo ora come possiamo utilizzare l' IOException generata , per creare un socket del server utilizzando la prima porta libera da un dato intervallo di numeri di porta:

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. Trovare un porto libero

L'uso di un numero di porta esplicito non è sempre una buona opzione, quindi esaminiamo le possibilità per allocare automaticamente una porta libera.

3.1. Semplice Java

Possiamo usare uno speciale numero di porta zero nel costruttore della classe ServerSocket . Di conseguenza, l' API java.net assegnerà automaticamente una porta libera per noi:

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

3.2. Quadro di primavera

Il framework Spring contiene una classe SocketUtils che possiamo usare per trovare una porta libera disponibile. La sua implementazione interna utilizza la classe ServerSocket , come mostrato nei nostri esempi precedenti:

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. Altre implementazioni del server

Diamo ora un'occhiata ad alcune altre implementazioni di server popolari.

4.1. Molo

Jetty è un server incorporato molto popolare per applicazioni Java. Assegnerà automaticamente una porta libera per noi a meno che non la impostiamo esplicitamente tramite il metodo setPort della classe 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

Tomcat, un altro popolare server Java incorporato, funziona in modo leggermente diverso. Possiamo specificare un numero di porta esplicito tramite il metodo setPort della classe Tomcat . Nel caso in cui forniamo un numero di porta zero, Tomcat assegnerà automaticamente una porta libera. Tuttavia, se non si imposta alcun numero di porta, Tomcat utilizzerà la porta predefinita 8080. Si noti che la porta Tomcat predefinita potrebbe essere occupata da altre applicazioni:

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. conclusione

In questo articolo, abbiamo esplorato come controllare lo stato di una porta specifica. Abbiamo anche spiegato come trovare una porta libera da una serie di numeri di porta e spiegato come utilizzare una porta libera assegnata automaticamente.

Negli esempi, abbiamo coperto la classe ServerSocket di base dall'API java.net e altre implementazioni di server popolari, inclusi Jetty e Tomcat.

Come sempre, il codice sorgente completo è disponibile su GitHub.