如何使用 Java 以编程方式确定给定机器中端口的可用性?
即给定一个端口号,确定它是否已经被使用?
/**
* 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;
}
他们也在检查 DatagramSocket 以检查端口是否在 UDP 和 TCP 中可用。
希望这可以帮助。
对于 Java 7,您可以使用 try-with-resource 获得更紧凑的代码:
private static boolean available(int port) {
try (Socket ignored = new Socket("localhost", port)) {
return false;
} catch (IOException ignored) {
return true;
}
}
如果您不太关心性能,您可以随时尝试使用ServerSocket类监听端口。如果它抛出异常,则它正在被使用。
public static boolean isAvailable(int portNr) {
boolean portFree;
try (var ignored = new ServerSocket(portNr)) {
portFree = true;
} catch (IOException e) {
portFree = false;
}
return portFree;
}
编辑:如果您要做的只是选择一个自由端口,那么new ServerSocket(0)
会为您找到一个。
从 Java 7 开始,David Santamaria 的答案似乎不再可靠。但是,看起来您仍然可以可靠地使用 Socket 来测试连接。
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);
}
}
}
}
以下解决方案的灵感来自 Spring-core(Apache 许可)的SocketUtils实现。
与使用Socket(...)
它的其他解决方案相比,它非常快(在不到一秒的时间内测试 1000 个 TCP 端口)。
当然,它只能检测在所有接口上打开端口或在 localhost 上显式运行的服务。
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;
}
}
基于 try/catch 套接字的解决方案可能不会产生准确的结果(套接字地址是“localhost”,并且在某些情况下,端口可能不会被环回接口“占用”,至少在 Windows 上我已经看到此测试失败,即prot 被错误地声明为可用)。
有一个很酷的库,名为SIGAR,下面的代码可以帮你搞定:
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;
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;
}
}
这仍然取决于 user207421 在对 David Santamaria 的回答的评论中指出的竞争条件(在此方法关闭ServerSocket
andDatagramSocket
并返回后,某些东西可能会抢占端口)。
就我而言,它有助于尝试连接到端口 - 如果服务已经存在,它会响应。
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);
}
就我而言,我必须使用 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;
}
}
不要忘记先导入
import java.net.DatagramSocket;
import java.net.BindException;
import java.net.SocketException;
我已经尝试过这样的事情,它对我来说真的很好
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");
}