Wie bestimme ich programmgesteuert die Verfügbarkeit eines Ports in einer bestimmten Maschine mit Java?
wenn Sie eine Portnummer angeben, bestimmen Sie, ob sie bereits verwendet wird oder nicht.
Dies ist die Implementierung , die vom Apache Camel -Projekt stammt:
/**
* 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;
}
Sie prüfen auch das DatagramSocket, um zu prüfen, ob der Port in UDP und TCP verfügbar ist.
Hoffe das hilft.
Für Java 7 können Sie try-with-resource für kompakteren Code verwenden:
private static boolean available(int port) {
try (Socket ignored = new Socket("localhost", port)) {
return false;
} catch (IOException ignored) {
return true;
}
}
Es scheint, dass ab Java 7 die Antwort von David Santamaria nicht mehr zuverlässig funktioniert. Es sieht jedoch so aus, als könnten Sie einen Socket immer noch zuverlässig zum Testen der Verbindung verwenden.
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);
}
}
}
}
Wenn Sie sich nicht mit der Leistung beschäftigen, können Sie immer versuchen, einen Port mithilfe der Klasse ServerSocket zu überwachen. Wenn es eine Ausnahmewahrscheinlichkeit gibt, wird es verwendet.
boolean portTaken = false;
ServerSocket socket = null;
try {
socket = new ServerSocket(_port);
} catch (IOException e) {
portTaken = true;
} finally {
if (socket != null)
try {
socket.close();
} catch (IOException e) { /* e.printStackTrace(); */ }
}
EDIT: Wenn Sie nur einen freien Port auswählen, sucht new SocketServer(0)
einen für Sie.
Die folgende Lösung basiert auf der SocketUtils - Implementierung von Spring-Core (Apache-Lizenz).
Im Vergleich zu anderen Lösungen, die Socket(...)
verwenden, ist dies ziemlich schnell (1000 TCP Ports werden in weniger als einer Sekunde getestet):
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;
}
}
Die try/catch-Socket-basierten Lösungen liefern möglicherweise keine genauen Ergebnisse (die Socket-Adresse lautet "localhost") und in einigen Fällen könnte der Port nicht von der Loopback-Schnittstelle "belegt" sein, und zumindest unter Windows habe ich gesehen, dass dieser Test fehlschlägt der Prot fälschlicherweise als verfügbar deklariert).
Es gibt eine coole Bibliothek mit dem Namen SIGAR . Der folgende Code kann Sie anschließen:
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;
In meinem Fall half es, den Port zu versuchen und eine Verbindung herzustellen - wenn der Dienst bereits vorhanden ist, würde er antworten.
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);
}
In meinem Fall musste ich die DatagramSocket-Klasse verwenden.
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;
}
}
Vergiss nicht, zuerst zu importieren
import Java.net.DatagramSocket;
import Java.net.BindException;
import Java.net.SocketException;
Eine Bereinigung der Antwort von David Santamaria:
/**
* Check to see if a port is available.
*
* @param port
* the port to check for availability.
*/
public static boolean portIsAvailable(int port) {
try (var ss = new ServerSocket(port); var ds = new DatagramSocket(port)) {
return true;
} catch (IOException e) {
return false;
}
}
Dies unterliegt immer noch einer Race-Bedingung, auf die User207421 in den Kommentaren zu David Santamaria hingewiesen hat (etwas könnte den Port ergreifen, nachdem diese Methode die ServerSocket
und DatagramSocket
geschlossen und zurückgegeben hat).