笔者最近在做产品,其中一个环节用到ping测试主机是否在线。

开发环境:Windows 7 64bit+JDK1.8 x64

以下是检测主机是否在线,开发环境中测试通过

public static boolean hostAvailabilityCheck(String host,int timeout){
try {
InetAddress inet = InetAddress.getByName(host);
System.out.println("Sending Ping Request to " + inet);
if(inet.isReachable(timeout)){
System.out.println("Host is reachable");
return true;
}
} catch (IOException e) {
System.out.println("Host is NOT reachable");
e.printStackTrace();
}
return false;
}

正常运行结果

当在windows XP下就运行不正常了,inet.isReachable处始终返回false。Google了一番(java inetaddress isreachable windows xp did not work),

确定这是个bug,有可能是因为Microsoft放弃了Windows XP等不再维护的操作系统,Oracle公司也不再向后兼容这些系统了。网上反馈bug的比比皆是。

JDK-5061568 : java.net.InetAddress.isReachable() kills Windows networking文章说这个bug会一直重现(This bug can be reproduced always.)

JDK-5061571 : InetAddress#isReachable does not send PINGs but only TCP echos

JDK-6595834 : InetAddress.isReachable is not thread safe when using ICMP ECHO.

以上三篇文章就指出了这个方法存在的一些问题:非线程安全、只发送TCP ECHO,对于框架设计人员来说,作为客户端编程人员我们关注的是api是否

能够达到预期目的,可是jdk1.8.0_144仍旧没有解决这个问题。

笔者最终通过网络搜索,在stackoverflow上找到了解决方法。

解决方法一(推荐):

出处:Why does InetAddress.isReachable return false, when I can ping the IP address?

// in case of Linux change the 'n' to 'c' 如果是Linux系统,请将n改成c
Process p1 = java.lang.Runtime.getRuntime().exec("ping -n 1 www.google.com");
int returnVal = p1.waitFor();
boolean reachable = (returnVal==0);

windows系统批处理返回值非0即失败。所以,如果以上返回为0说明ping的通,如果返回2则失败。

解决方法二:

出处:Odd InetAddress.isReachable() issue

说明:需要第三方库JNA支持,需要一定的操作系统知识。此方法将会通过JNA调用COM组件来调用Windows API函数,

相关DLL是IPHLPAPI.DLL和 WSOCK32.DLL

public interface InetAddr extends StdCallLibrary {
InetAddr INSTANCE = (InetAddr)
Native.loadLibrary("wsock32.dll", InetAddr.class); ULONG inet_addr(String cp); //in_addr creator. Creates the in_addr C struct used below
} public interface IcmpEcho extends StdCallLibrary {
IcmpEcho INSTANCE = (IcmpEcho)
Native.loadLibrary("iphlpapi.dll", IcmpEcho.class); int IcmpSendEcho(
HANDLE IcmpHandle, //Handle to the ICMP
ULONG DestinationAddress, //Destination address, in the form of an in_addr C Struct defaulted to ULONG
Pointer RequestData, //Pointer to the buffer where my Message to be sent is
short RequestSize, //size of the above buffer. sizeof(Message)
byte[] RequestOptions, //OPTIONAL!! Can set this to NULL
Pointer ReplyBuffer, //Pointer to the buffer where the replied echo is written to
int ReplySize, //size of the above buffer. Normally its set to the sizeof(ICMP_ECHO_REPLY), but arbitrarily set it to 256 bytes
int Timeout); //time, as int, for timeout HANDLE IcmpCreateFile(); //win32 ICMP Handle creator boolean IcmpCloseHandle(HANDLE IcmpHandle); //win32 ICMP Handle destroyer
}
public void SendReply(String ipAddress) {
final IcmpEcho icmpecho = IcmpEcho.INSTANCE;
final InetAddr inetAddr = InetAddr.INSTANCE;
HANDLE icmpHandle = icmpecho.IcmpCreateFile();
byte[] message = new String("thisIsMyMessage!".toCharArray()).getBytes();
Memory messageData = new Memory(32); //In C/C++ this would be: void *messageData = (void*) malloc(message.length);
messageData.write(0, message, 0, message.length); //but ignored the length and set it to 32 bytes instead for now
Pointer requestData = messageData;
Pointer replyBuffer = new Memory(256);
replyBuffer.clear(256); // HERE IS THE NATIVE CALL!!
reply = icmpecho.IcmpSendEcho(icmpHandle,
inetAddr.inet_addr(ipAddress),
requestData,
(short) 32,
null,
replyBuffer,
256,
timeout);
// NATIVE CALL DONE, CHECK REPLY!! icmpecho.IcmpCloseHandle(icmpHandle);
} public boolean IsReachable () {
return (reply > 0);
}

笔者简单封装了一下代码

class IcmpEchoPatch{
int reply;
public void SendReply(String host,int timeout) {
final IcmpEcho icmpecho = IcmpEcho.INSTANCE;
final InetAddr inetAddr = InetAddr.INSTANCE;
HANDLE icmpHandle = icmpecho.IcmpCreateFile();
byte[] message = new String("thisIsMyMessage!".toCharArray()).getBytes();
Memory messageData = new Memory(32); //In C/C++ this would be: void *messageData = (void*) malloc(message.length);
messageData.write(0, message, 0, message.length); //but ignored the length and set it to 32 bytes instead for now
Pointer requestData = messageData;
Pointer replyBuffer = new Memory(256);
replyBuffer.clear(256); // HERE IS THE NATIVE CALL!!
reply = icmpecho.IcmpSendEcho(icmpHandle,
inetAddr.inet_addr(host),
requestData,
(short) 32,
null,
replyBuffer,
256,
timeout);
// NATIVE CALL DONE, CHECK REPLY!!
icmpecho.IcmpCloseHandle(icmpHandle);
} public boolean IsReachable () {
return (reply > 0);
}
}

最终hostAvailabilityCheck方法代码如下:

public static boolean hostAvailabilityCheck(String host,int timeout){
try { HardWareIdentifier resolver = HardWareIdentifier.getDefault(); //替换为你的方法
if(resolver.isMinSupportPlat()){ //替换为你的方法判断操作系统
IcmpEchoPatch ping = new IcmpEchoPatch();
ping.SendReply(host, timeout);
if(ping.IsReachable()){
System.out.println("Host is reachable");
return true;
}
}else{
InetAddress inet = InetAddress.getByName(host);
System.out.println("Sending Ping Request to " + inet);
if(inet.isReachable(timeout)){
System.out.println("Host is reachable");
return true;
}
}
} catch (IOException e) {
System.out.println("Host is NOT reachable");
e.printStackTrace();
}
return false;
}

解决InetAddress.isReachable(timeout)在windows xp始终返回false的bug的更多相关文章

  1. 解决libcurl7.50.3在windows XP SP3 VC++ 6.0下编译报错 unresolved external symbol __imp__IdnToAscii@20 unresolved external symbol __imp__IdnToUnicode@20

    错误重现: --------------------Configuration: curl - Win32 LIB Debug DLL Windows SSPI DLL WinIDN--------- ...

  2. $(this).form("validate") 始终返回false

    onsubmit 提交前触发,返回 false 来阻止提交动作. validate 进行表单字段验证,当全部字段都有效时返回 true .该方法和 validatebox 插件一起使用. 解决:注释掉 ...

  3. MDAC 在WINDOWS XP SP3 不能安装 的解决方法

    MDAC 在WINDOWS XP SP3 不能安装 的解决方法 解决步骤如下: c:/windows/inf 下找出mdac.inf 然后点右键->安装.在弹出提示路径选取c:/windows/ ...

  4. Windows XP忘记密码的几种解决方法

    1. 问题 朋友一Windows XP系统的密码忘记了,让给解决一下.网上搜索了几种解决方案,列在下面,记一下. 2. 解决 2.1 使用“Administrator”帐户 前提:当前用户名不是“Ad ...

  5. WINDOWS XP 系统显示乱码的解决方法(修改注册表,使用正常字体)

            一位同事的计算机进入WINDOWS XP系统后,电脑里的所有汉字全部显示乱码,很多办公文档无法打开而影响工作.因为第一次遇到这种问题,当然首先是百度解决了,搜索了相关的信息后找到了答案 ...

  6. 解决 Windows XP 下 IIS 最大连接数为 10 的问题

    为了方便调试网站程序,就在 Windows XP 系统下安装了 IIS,但是出现了一个问题:“403.9 误-禁止访问:连接的用户过多”,会有这样的问题出现,一般有两种可能:一.IIS 本身的最大连接 ...

  7. Windows XP 每次开机都自动检测硬盘 解决办法(可以用HDDRegenerate修复坏道)

    Windows XP,每次开机都自动检测硬盘,之前正常关机,没有任何非法操作.Windows XP,每次开机都自动检测硬盘,之前正常关机,没有任何非法操作. 1.和硬盘的分区格式有关,FAT32格式在 ...

  8. 解决vista和win7在windows服务中交互桌面权限问题:穿透Session 0 隔离

        在某国外大型汽车公司BI项目中,有一个子项目,需要通过大屏幕展示销售报表,程序需要自动启动和关闭.开发人员在开发过程中,发现在Win7的service中不能直接操作UI进程,调查过程中,发现如 ...

  9. [转]解决vista和win7在windows服务中交互桌面权限问题:穿透Session 0 隔离

    服务(Service)对于大家来说一定不会陌生,它是Windows 操作系统重要的组成部分.我们可以把服务想像成一种特殊的应用程序,它随系统的“开启-关闭”而“开始-停止”其工作内容,在这期间无需任何 ...

随机推荐

  1. C语言数据结构基础学习笔记——树

    树是一种一对多的逻辑结构,树的子树之间没有关系. 度:结点拥有的子树数量. 树的度:树中所有结点的度的最大值. 结点的深度:从根开始,自顶向下计数. 结点的高度:从叶结点开始,自底向上计数. 树的性质 ...

  2. Java进程&线程(整理)

    Java进程&线程 程序:程序员写的代码,就是代码,不运行好像不会发生什么: 进程:一个进程可以理解为"运行的"一个程序,当我们启动一个java程序后,对应的jvm就会创建 ...

  3. hashcode()和equals()

    一.equal()方法 Object类中equals()方法实现如下: public boolean equals(Object obj) { return (this == obj); } 通过该实 ...

  4. net.sf.json

    JSONObject package com.itlwc.test;         import net.sf.json.JSONArray;    import net.sf.json.JSONO ...

  5. nginx访问统计

    1).根据访问IP统计UV awk '{print $1}'  access.log|sort | uniq -c |wc -l 2).统计访问URL统计PV awk '{print $7}' acc ...

  6. Django Cookie和Seesion

    1.cookie不属于http协议范围,由于http协议无法保持状态,但实际情况,我们却又需要“保持状态”,因此cookie就是在这样一个场景下诞生.cookie的工作原理是:由服务器产生内容,浏览器 ...

  7. Centos7】hostnamectl 设置主机名

    Centos7中提供了设置主机名的工具 hostnamectl hostname有三种状态 static(永久) transient(瞬态) pretty (灵活) 查看主机名状态 [oracle@h ...

  8. 用原生js简单模仿angular的依赖注入

    大家都知道angular 依赖注入很神奇,跟我们平常写代码的风格思维差别很大,不过仔细分析确是一个很有意思的东西,依赖注入早期也叫依赖倒置,是java中有的.废话不多少直接上例子 本帖属于原创,转载请 ...

  9. Autofac使用代码方式进行组件注册【不需要依赖】

    public class AutofacFactory2     {         IBank bank;         public AutofacFactory2()         {    ...

  10. Echart ,X轴显示的为tooltip内显示的一部分内容放在上面显示的一部分如下图所示

    如图所示:X轴只显示tooltip部分内容解决方案 在xAxis下面,实现方法如下 axisLabel: { interval: 0, formatter:function(value) { var ...