笔者最近在做产品,其中一个环节用到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. new words

    Your cooperation is greatly appreciated 感谢您的合作! budget 预算

  2. 用SVG做background image

    1 用utf8格式, 需要 双引号“”替换为单引号,而且采用url encode编码,例如# 替换为 %23, body { background-image: url("data:imag ...

  3. Pycharm去掉项目所有 # 注释

    通过快捷键ctrl+shift+R 进入 项目全局替换窗口,点击右上角 勾选正则,然后 搜索框输入 (#.*) 即可 ,然后点击 replace all 去掉所有注释

  4. http(数据格式)、postman(数组、id、断言) 小知识必看啊

  5. MindFusion 中节点关键路径的遍历

    工作中总能遇到 一些 奇葩的需求,提出这些奇葩需求的人,多半也是奇葩的人,要么不懂相关的计算机软件知识,要么就是瞎扯蛋,异想天开,然而这些奇葩的需求,我也总能碰到.言规正传,在一次项目中,使用了 Mi ...

  6. debian apache2 多端口对应多文件 虚拟端口配置

    apache2单IP多端口创建虚拟站点如下: 1.转到配制目录虚拟站点配制目录 cd /etc/apache2/ ​ 2.配置新增多的端口 编辑上级目录中的端口配制文件sudo gedit ports ...

  7. Machine.config 文件中节点<machineKey>的强随机生成

    Machine.config 文件中节点<machineKey>的强随机生成 <machineKey>这个节允许你设置用于加密数据和创建数字签名的服务器特定的密钥.ASP.NE ...

  8. win10 .net3.5的问题及解决方案

    近日有网友反映在windows10_64位系统电脑上安装Net framework3.5,操作时总失败,怎么办呢?小编下面就介绍win10 64位系统无法安装Net framework3.5的两种解决 ...

  9. sys模块学习记录

    import sys s = sys.argv #命令行参数List,第一个元素是程序本身路径 #sys.exit() #退出程序,正常退出时exit(0) s = sys.version #获取Py ...

  10. OpenStack构架简介

    OpenStack既是一个社区,也是一个项目和一个开源软件,提供开放源码软件,建立公共和私有云,它提供了一个部署云的操作平台或工具集,其宗旨在于:帮助组织运行为虚拟计算或存储服务的云,为公有云.私有云 ...