Come si determina a livello di codice la disponibilità di una porta in una determinata macchina utilizzando Java?
vale a dire dato un numero di porta, determinare se è già in uso o no ?.
Come si determina a livello di codice la disponibilità di una porta in una determinata macchina utilizzando Java?
vale a dire dato un numero di porta, determinare se è già in uso o no ?.
Risposte:
Questa è l' implementazione proveniente dal progetto Apache camel :
/**
* 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;
}
Stanno controllando anche DatagramSocket per verificare se la porta è disponibile in UDP e TCP.
Spero che questo ti aiuti.
ServerSocket
ascolto per qualche porta, è quello che dovrebbe fare e restituire il file ServerSocket
. Crearlo e poi chiuderlo e restituirlo non garantisce che un successivo ServerSocket
possa essere creato utilizzando quella porta. Idem per DatagramSocket
.
Per Java 7 puoi usare try-with-resource per un codice più compatto:
private static boolean available(int port) {
try (Socket ignored = new Socket("localhost", port)) {
return false;
} catch (IOException ignored) {
return true;
}
}
ConnectException: 'connection refused'
sì, dovrebbe restituire falso. Per i timeout, nulla che potrebbe restituire sarebbe valido, poiché la risposta effettiva non è nota. Ecco perché questa tecnica è inutile per questo scopo.
Sembra che a partire da Java 7, la risposta di David Santamaria non funzioni più in modo affidabile. Tuttavia, sembra che tu possa ancora utilizzare in modo affidabile un Socket per testare la connessione.
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);
}
}
}
}
Se non sei troppo interessato alle prestazioni, puoi sempre provare ad ascoltare su una porta utilizzando la classe ServerSocket . Se genera un'eccezione, le probabilità sono che venga utilizzato.
public static boolean isAvailable(int portNr) {
boolean portFree;
try (var ignored = new ServerSocket(portNr)) {
portFree = true;
} catch (IOException e) {
portFree = false;
}
return portFree;
}
EDIT: Se tutto ciò che stai cercando di fare è selezionare una porta libera, new ServerSocket(0)
ne troverai una per te.
La seguente soluzione è ispirata all'implementazione SocketUtils di Spring-core (licenza Apache).
Rispetto ad altre soluzioni che lo utilizzano Socket(...)
è piuttosto veloce (testare 1000 porte TCP in meno di un secondo):
public static boolean isTcpPortAvailable(int port) {
try (ServerSocket serverSocket = new ServerSocket()) {
// setReuseAddress(false) is required only on OSX,
// 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;
}
}
Le soluzioni basate su socket try / catch potrebbero non fornire risultati accurati (l'indirizzo del socket è "localhost" e in alcuni casi la porta potrebbe essere "occupata" non dall'interfaccia di loopback e almeno su Windows ho visto che questo test fallisce, ad es. il prot falsamente dichiarato disponibile).
C'è una bella libreria chiamata SIGAR , il seguente codice può collegarti:
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;
Una pulizia della risposta segnalata da 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;
}
}
Questo è ancora soggetto a una condizione di gara segnalata dall'utente207421 nei commenti alla risposta di David Santamaria (qualcosa potrebbe afferrare il port dopo che questo metodo chiude ServerSocket
e DatagramSocket
e ritorna).
Nel mio caso è stato utile provare a connettersi alla porta: se il servizio è già presente, risponderebbe.
try {
log.debug("{}: Checking if port open by trying to connect as a client", portNumber);
Socket sock = new Socket("localhost", portNumber);
sock.close();
log.debug("{}: Someone responding on port - seems not open", portNumber);
return false;
} catch (Exception e) {
if (e.getMessage().contains("refused")) {
return true;
}
log.error("Troubles checking if port is open", e);
throw new RuntimeException(e);
}
Nel mio caso ho dovuto usare la classe DatagramSocket.
boolean isPortOccupied(int port) {
DatagramSocket sock = null;
try {
sock = new DatagramSocket(port);
sock.close();
return false;
} catch (BindException ignored) {
return true;
} catch (SocketException ex) {
System.out.println(ex);
return true;
}
}
Non dimenticare di importare prima
import java.net.DatagramSocket;
import java.net.BindException;
import java.net.SocketException;
Ho provato qualcosa di simile e ha funzionato molto bene con me
Socket Skt;
String host = "localhost";
int i = 8983; // port no.
try {
System.out.println("Looking for "+ i);
Skt = new Socket(host, i);
System.out.println("There is a Server on port "
+ i + " of " + host);
}
catch (UnknownHostException e) {
System.out.println("Exception occured"+ e);
}
catch (IOException e) {
System.out.println("port is not used");
}