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

    FPGA中,经常会用到FIFO来缓冲数据或者跨时钟传递数据. 1.Almost full & Almost empty 作为初学者,最开始使用FIFO的时候,对于它的理解,无非是配置好位宽.深 ...

  2. IDEA 倒入maven项目下载很慢

    1.找到安装maven的路径 2.直接搜索settings.xml文件 <mirror> <!--This sends everything else to /public --&g ...

  3. [UnityShader基础]07.MaterialPropertyDrawer

    参考链接: https://blog.csdn.net/e295166319/article/details/60141677 https://docs.unity3d.com/ScriptRefer ...

  4. (5/24) 模块化:实现快速CSS文件打包

    写在前面:为了兼容,此处的webpack版本为3.6.0.webpack-dev-server版本为2.9.7.css-loader版本为2.0.0.style-loader版本为0.23.1,若在下 ...

  5. 原生js开发vue的双向数据绑定

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...

  6. 服务器硬盘--SAS盘和SATA盘

    一.SAS和SATA SATA: Serial Advanced Technology Attachment,又叫串口硬盘,是将主机总线适配器连接到硬盘的总线接口. SAS: Serial Attac ...

  7. 'Settings' object has no attribute 'FYFQ_URL_test'

    读取django settings内容时报错: 'Settings' object has no attribute 'FYFQ_URL_test' 原因:settings中的变量,必须都是大写

  8. 解析如何实现微信唤醒默认浏览器下载app教程!

    前言 现如今微信对第三方app下载链接的拦截是越来越严格了,下载链接在微信中分享转发经常会被拦截,一旦被拦截用户就只能复制链接手动打开浏览器粘贴才能访问,如此给用户带来的体验台差,用户量无法有效地累积 ...

  9. js:获取事件源的兼容性写法

    XXX.onclick = function(e){ var event = e || window.event; var target = event.target || event.srvElem ...

  10. 算法之Python实现 - 000

    Python的火热已极,几乎人人在学Python,为了节约时间,也为了实现Python的代码量,计划从今天开始,将<算法与数据结构题目最优解>一书中的代码全部用Python实现.