Java 實(shí)現(xiàn) Ping 功能

在項(xiàng)目中需要判斷目錄服務(wù)器是否在線,需要用到ping命令。
為了使用java來(lái)實(shí)現(xiàn)ping的功能,有人推薦使用java的
Runtime.exec()方法來(lái)直接調(diào)用系統(tǒng)的Ping命令,也有人完成了純Java實(shí)現(xiàn)Ping的程序,使用的是Java的NIO包(native
io, 高效IO包)。但是設(shè)備檢測(cè)只是想測(cè)試一個(gè)遠(yuǎn)程主機(jī)是否可用。所以,可以使用以下三種方式來(lái)實(shí)現(xiàn):?
1.使用InetAddress實(shí)現(xiàn)Ping
public?static?boolean?ping(String ipAddress)?throws?Exception {
????int??timeOut = 3000?; //超時(shí)應(yīng)該在3鈔以上
????boolean?status = InetAddress.getByName(ipAddress).isReachable(timeOut);
????// 當(dāng)返回值是true時(shí),說(shuō)明host是可用的,false則不可。
????return?status;
}isReachable方法在Windows系統(tǒng)平臺(tái)上的實(shí)現(xiàn)(native c)并沒(méi)有使用ICMP,而是全完使用連接echo端口7?的方法。Native的實(shí)現(xiàn)源碼:
/*
?* Windows implementation of ICMP & RAW sockets is too unreliable for now.
?* Therefore it's best not to try it at all and rely only on TCP
?* We may revisit and enable this code in the future.
?*/??
??
/* Can't create a raw socket, so let's try a TCP socket */??
??
him.sin_port = htons(7); /* Echo */???
connect_rv = connect(fd, (struct?sockaddr *)&him, len);InetAddress.isReachable()通過(guò)試圖連接TCP端口的方法是利用了TCP/IP協(xié)議的三次握手原理,即使對(duì)方機(jī)器在端口上沒(méi)有服務(wù),當(dāng)接收到請(qǐng)求時(shí)會(huì)立刻拒絕,如果對(duì)方機(jī)器不在網(wǎng)絡(luò)上則結(jié)果是超時(shí)!這個(gè)方法的實(shí)現(xiàn)正是利用了這一點(diǎn)。引用OpenJDK 6,isReachable()方法native c實(shí)現(xiàn)的一段注釋?zhuān)?/p>
/**
?* connection established or refused immediately, either way it means
?* we were able to reach the host!
?*/
還有一個(gè)問(wèn)題就是超時(shí)時(shí)間的設(shè)置,受網(wǎng)絡(luò)影響,TCP建立連接的3次握手耗時(shí)不確定,例如:

3次握手耗時(shí)700ms,如果我們?cè)O(shè)置的超時(shí)時(shí)間比700ms小,返回的也是false,從而造成誤報(bào)。
2.調(diào)用CMD
通過(guò)程序調(diào)用類(lèi)似“ping 127.0.0.1 -n 10?-w 3000”的命令,該命令ping10次,等待每個(gè)響應(yīng)的超時(shí)時(shí)間3秒。?網(wǎng)絡(luò)通的情況會(huì)輸出:
C:\Users\tgg>ping 127.0.0.1 -n 10 -w 3000 正在 Ping 127.0.0.1 具有 32 字節(jié)的數(shù)據(jù):
來(lái)自 127.0.0.1 的回復(fù): 字節(jié)=32 時(shí)間<1ms TTL=64 來(lái)自 127.0.0.1 的回復(fù): 字節(jié)=32 時(shí)間<1ms TTL=64
來(lái)自 127.0.0.1 的回復(fù): 字節(jié)=32 時(shí)間<1ms TTL=64 來(lái)自 127.0.0.1 的回復(fù): 字節(jié)=32 時(shí)間<1ms TTL=64
來(lái)自 127.0.0.1 的回復(fù): 字節(jié)=32 時(shí)間<1ms TTL=64 來(lái)自 127.0.0.1 的回復(fù): 字節(jié)=32 時(shí)間<1ms TTL=64
?來(lái)自 127.0.0.1 的回復(fù): 字節(jié)=32 時(shí)間<1ms TTL=64 來(lái)自 127.0.0.1 的回復(fù): 字節(jié)=32 時(shí)間<1ms TTL=64
來(lái)自 127.0.0.1 的回復(fù): 字節(jié)=32 時(shí)間<1ms TTL=64 來(lái)自 127.0.0.1 的回復(fù): 字節(jié)=32 時(shí)間<1ms TTL=64
127.0.0.1 的 Ping 統(tǒng)計(jì)信息: 數(shù)據(jù)包: 已發(fā)送 = 10,已接收 = 10,丟失 = 0 (0% 丟失), 往返行程的估
計(jì)時(shí)間(以毫秒為單位): 最短 = 0ms,最長(zhǎng) = 0ms,平均 = 0ms以上信息輸出是根據(jù)操作系統(tǒng)的語(yǔ)言來(lái)進(jìn)行本地化的,其中"ms TTL="是不變的,我們可以通過(guò)Runtime.exec方法來(lái)調(diào)用本地CMD命令來(lái)執(zhí)行以上語(yǔ)句,代碼如下:
import?org.apache.log4j.Logger;
import?java.io.BufferedReader;
import?java.io.IOException;
import?java.io.InputStreamReader;
import?java.net.InetAddress;
import?java.util.regex.Matcher;
import?java.util.regex.Pattern;
/** * @author?tgg */
?
public?class?Ping?{
?
????public?static?boolean?ping(String ipAddress)?throws?Exception {
????????int?timeOut = 3000?;
????????boolean?status = InetAddress.getByName(ipAddress).isReachable(timeOut);
????????return?status;
????}
?
????public?static?boolean?ping(String ipAddress, int?pingTimes, int?timeOut)?{
????????BufferedReader in = null;
????????Runtime r = Runtime.getRuntime();
????????// 將要執(zhí)行的ping命令,此命令是windows格式的命令
????????String pingCommand = "ping "?+ ipAddress + " -n "?+ pingTimes + " -w "?+ timeOut;
????????// Linux命令如下
????????// String pingCommand = "ping" -c " + pingTimes + " -w " + timeOut + ipAddress;
????????try?{
????????????if?(logger.isDebugEnabled()) {
????????????????logger.debug(pingCommand);
????????????}
????????????// 執(zhí)行命令并獲取輸出
????????????Process p = r.exec(pingCommand);
????????????if?(p == null) {
????????????????return?false;
????????????}
????????????in = new?BufferedReader(new?InputStreamReader(p.getInputStream()));
????????????int?connectedCount = 0;
????????????String line;
????????????// 逐行檢查輸出,計(jì)算類(lèi)似出現(xiàn)=23ms TTL=62字樣的次數(shù)
????????????while?((line = in.readLine()) != null) {
????????????????connectedCount += getCheckResult(line);
????????????}
????????????// 如果出現(xiàn)類(lèi)似=23ms TTL=62這樣的字樣,出現(xiàn)的次數(shù)=測(cè)試次數(shù)則返回真
????????????return?connectedCount == pingTimes;
????????} catch?(Exception e) {
????????????logger.error(e);
????????????return?false;
????????} finally?{
????????????try?{
????????????????in.close();
????????????} catch?(IOException e) {
????????????????logger.error(e);
????????????}
????????}
????}
????//若line含有=18ms TTL=16字樣,說(shuō)明已經(jīng)ping通,返回1,否則返回0.
????private?static?int?getCheckResult(String line)?{ // System.out.println("控制臺(tái)輸出的結(jié)果為:"+line);
????????Pattern pattern = Pattern.compile("(\\d+ms)(\\s+)(TTL=\\d+)", Pattern.CASE_INSENSITIVE);
????????Matcher matcher = pattern.matcher(line);
????????while?(matcher.find()) {
????????????return?1;
????????}
????????return?0;
????}
?
????private?static?final?Logger logger = Logger.getLogger(Ping.class);
}3.Java調(diào)用控制臺(tái)執(zhí)行ping命令
具體的思路是這樣的:
通過(guò)程序調(diào)用類(lèi)似“ping 127.0.0.1 -n 10 -w
4”的命令,這命令會(huì)執(zhí)行ping十次,如果通順則會(huì)輸出類(lèi)似“來(lái)自127.0.0.1的回復(fù):字節(jié)=32 時(shí)間<1ms
TTL=64”的文本(具體數(shù)字根據(jù)實(shí)際情況會(huì)有變化),其中中文是根據(jù)環(huán)境本地化的,有些機(jī)器上的中文部分是英文,但不論是中英文環(huán)境,
后面的“<1ms
TTL=62”字樣總是固定的,它表明一次ping的結(jié)果是能通的。如果這個(gè)字樣出現(xiàn)的次數(shù)等于10次即測(cè)試的次數(shù),則說(shuō)明127.0.0.1是百分之百能連通的。?
技術(shù)上:具體調(diào)用dos命令用Runtime.getRuntime().exec實(shí)現(xiàn),查看字符串是否符合格式用正則表達(dá)式實(shí)現(xiàn)。
見(jiàn)Ping類(lèi)的ping(String,int,int)函數(shù)。
import?java.io.BufferedReader;
import?java.io.IOException;
import?java.io.InputStreamReader;
import?java.net.InetAddress;
import?java.net.UnknownHostException;
import?java.util.regex.Matcher;
import?java.util.regex.Pattern;
?
public?class?Ping?{
????
????public?static?boolean?ping(String ipAddress)?throws?Exception {
????????int??timeOut = 3000?; //超時(shí)應(yīng)該在3鈔以上
????????boolean?status = InetAddress.getByName(ipAddress).isReachable(timeOut); // 當(dāng)返回值是true時(shí),說(shuō)明host是可用的,false則不可。
????????return?status;
????}
????
????public?static?void?ping02(String ipAddress)?throws?Exception {
????????String line = null;
????????try?{
????????????Process pro = Runtime.getRuntime().exec("ping "?+ ipAddress);
????????????BufferedReader buf = new?BufferedReader(new?InputStreamReader(
????????????????????pro.getInputStream()));
????????????while?((line = buf.readLine()) != null)
????????????????System.out.println(line);
????????} catch?(Exception ex) {
????????????System.out.println(ex.getMessage());
????????}
????}
????
????public?static?boolean?ping(String ipAddress, int?pingTimes, int?timeOut)?{
????????BufferedReader in = null;
????????Runtime r = Runtime.getRuntime(); // 將要執(zhí)行的ping命令,此命令是windows格式的命令
????????String pingCommand = "ping "?+ ipAddress + " -n "?+ pingTimes + " -w "?+ timeOut;
????????try?{ // 執(zhí)行命令并獲取輸出
????????????System.out.println(pingCommand);
????????????Process p = r.exec(pingCommand);
????????????if?(p == null) {
????????????????return?false;
????????????}
????????????in = new?BufferedReader(new?InputStreamReader(p.getInputStream())); // 逐行檢查輸出,計(jì)算類(lèi)似出現(xiàn)=23ms TTL=62字樣的次數(shù)
????????????int?connectedCount = 0;
????????????String line = null;
????????????while?((line = in.readLine()) != null) {
????????????????connectedCount += getCheckResult(line);
????????????} // 如果出現(xiàn)類(lèi)似=23ms TTL=62這樣的字樣,出現(xiàn)的次數(shù)=測(cè)試次數(shù)則返回真
????????????return?connectedCount == pingTimes;
????????} catch?(Exception ex) {
????????????ex.printStackTrace(); // 出現(xiàn)異常則返回假
????????????return?false;
????????} finally?{
????????????try?{
????????????????in.close();
????????????} catch?(IOException e) {
????????????????e.printStackTrace();
????????????}
????????}
????}
????//若line含有=18ms TTL=16字樣,說(shuō)明已經(jīng)ping通,返回1,否則返回0.
????private?static?int?getCheckResult(String line)?{ // System.out.println("控制臺(tái)輸出的結(jié)果為:"+line);
????????Pattern pattern = Pattern.compile("(\\d+ms)(\\s+)(TTL=\\d+)", Pattern.CASE_INSENSITIVE);
????????Matcher matcher = pattern.matcher(line);
????????while?(matcher.find()) {
????????????return?1;
????????}
????????return?0;
????}
????public?static?void?main(String[] args)?throws?Exception {
????????String ipAddress = "127.0.0.1";
????????System.out.println(ping(ipAddress));
????????ping02(ipAddress);
????????System.out.println(ping(ipAddress, 5, 5000));
????}
}第一種方法:Jdk的InetAddresss,代碼簡(jiǎn)單。
第二種方法:使用java調(diào)用cmd命令,這種方式最簡(jiǎn)單,可以把ping的過(guò)程顯示在本地。
第三種方法:也是使用java調(diào)用控制臺(tái)的ping命令,這個(gè)比較可靠,還通用,使用起來(lái)方便:傳入個(gè)ip,設(shè)置ping的次數(shù)和超時(shí),就可以根據(jù)返回值來(lái)判斷是否ping通。
出處:blog.csdn.net/zeb_perfect/article/details/50133199
關(guān)注GitHub今日熱榜,專(zhuān)注挖掘好用的開(kāi)發(fā)工具,致力于分享優(yōu)質(zhì)高效的工具、資源、插件等,助力開(kāi)發(fā)者成長(zhǎng)!
點(diǎn)個(gè)在看 你最好看

