笔者最近在做产品,其中一个环节用到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. Cesium学习网址

    不错的案例介绍: 根据地形瓦片直接绘制高程.坡度及等高线 同一场景下显示两个不同的瓦片图层 https://cloud.tencent.com/developer/article/1113355 绘制 ...

  2. 问题-python3.6找不到tkinter

    问题:import tkinter失败 然后直接pip安装也不ok python3.6安装过程中会提示是否选择安装tkinter,如此只有打开原来的安装程序 勾选箭头所示

  3. Maven 下添加oracle11g的包 报Missing artifact com.oracle:ojdbc6:jar:11.2.0.1.0

    Missing artifact com.oracle:ojdbc6:jar:11.2.0.1.0 原因:Oracle 的ojdbc.jar是收费的,所以maven的中央仓库中没有这个资源,只能通过配 ...

  4. HTML5+CSS3(3)

    一.CSS3新增属性用法整理 1.box-shadow(阴影效果) 2.border-color(为边框设置多种颜色) 3.border-image(图片边框) 4.text-shadow(文本阴影) ...

  5. 【HDFS API编程】删除文件

    所有操作都是以fileSystem为入口进行,我们使用fileSystem下的delete方法进行删除文件操作,删除的时候必须慎重. 直接上代码: /** * 删除文件 * @throws Excep ...

  6. java面试总结(资料来源网络)

    core java: 一.集合 1.hashMap 结构如图: HashMap在Map.Entry静态内部类实现中存储key-value对. HashMap使用哈希算法.在put和get方法中.它使用 ...

  7. The type initializer for System.Data.SqlClient.SqlConnection threw an exception

    The type initializer for System.Data.SqlClient.SqlConnection threw an exception net framwork啥原因 xp电脑

  8. vue源码逐行注释分析+40多m的vue源码程序流程图思维导图 (diff部分待后续更新)

    vue源码业余时间差不多看了一年,以前在网上找帖子,发现很多帖子很零散,都是一部分一部分说,断章的很多,所以自己下定决定一行行看,经过自己坚持与努力,现在基本看完了,差ddf那部分,因为考虑到自己要换 ...

  9. MySQL Windows环境变量设置

    问题:MySQL无法全局使用 1.查找MySQL路径 2.添加环境变量 3.验证功能

  10. Hibernate 中出现 users is not mapped 问题

    Hibernate 中出现 users is not mapped 问题: 解答:HQL语句中表名应该是ORM映射的类名,所以应该改成:  (如果是用注解生成实体类,那就是注解的那个类)String ...