有時候需要判斷本地的某一個端口號是否被占用,網上通用的一種方法是:
public boolean isPortAvailable(int port) {
try {
ServerSocket server = new ServerSocket(port);
System.out.println("The port is available.");
return true;
} catch (IOException e) {
System.out.println("The port is occupied.");
}
return false;
}
通過新建一個ServerSocket來判斷端口是否被占用,但是實際上這個檢測方式是有漏洞的,有些情況不能夠覆蓋得到。例如,一個運行在WebLogic之上的應用它的端口為8406,則通過命令
netstat -aon | findstr 8406
得到的結果可能為:
TCP 192.168.1.101:8406 111.111.111.111:80 SYN_SENT 112
可見8406綁定的內部IP地址為本機的IP地址192.168.1.101,這時通過如上的方式得到的結果為這個端口沒有被使用。原因在於通過ServerSocket建立的連接綁定的IP為0.0.0.0,這一小小的差異導致了如上方法沒有通用性,找到一種比較好的方法為:
private void bindPort(String host, int port) throws Exception {
Socket s = new Socket();
s.bind(new InetSocketAddress(host, port));
s.close();
}
public boolean isPortAvailable(int port) {
Socket s = new Socket();
try {
bindPort("0.0.0.0", port);
bindPort(InetAddress.getLocalHost().getHostAddress(), port);
return true;
} catch (Exception e) {
return false;
}
}
通過一個socket分別嘗試去綁定0.0.0.0和本機IP上的port,當這兩個port都可以被綁定時,則這個端口真的沒有被占用。在linux上這一方法同樣適用,但是有一種情況需要注意,當本機通過hostname不能解析到本機的IP地址時InetAddress.getLocalHost().getHostAddress()這個函數會拋錯,導致從結果來看端口被占用著。因此需要確保在/etc/hosts文件中存在著這麼一條映射:
<hostname> <local_ip>
<hostname>為你在終端執行hostname返回的本機名,<local_ip>則為在終端執行ifconfig得到的本機真實IP,JAVA提供的這個函數會去這個文件中找<hostname>對應的IP地址,不然會因為找不到而拋錯。確保這一條之後,在linux上也能正確檢測指定端口的占用情況~