InetAddress isReachable 方法是否有最短超时时间?

Is there a minimum timeout to InetAddress isReachable method?

我在使用 InetAddress class 的 isReachable 方法时出现了奇怪的行为。

Method prototype 是:

public boolean isReachable(int timeout)

代码很简单:

    InetAddress addr = null;
    String ip = "10.48.2.169";

    try {
        addr = InetAddress.getByName(ip);
    } catch (UnknownHostException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

    Timestamp s = new Timestamp(System.currentTimeMillis());
    System.out.println(s + "\t Starting tests :");

    pingTest(addr, 100);
    pingTest(addr, 500);
    pingTest(addr, 1000);
    pingTest(addr, 1500);
    pingTest(addr, 2000);
    pingTest(addr, 2500);

其中 pingTest 定义为:

public static void pingTest(InetAddress addr, int timeout) {
        boolean result = false;
        try {
            result = addr.isReachable(timeout);
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        Timestamp s = new Timestamp(System.currentTimeMillis());
        System.out.println(s + "\t (" + timeout + ") " + addr.toString() + " " + result);
    }

则输出为:

2017-09-07 16:45:41.573  Starting tests :
2017-09-07 16:45:42.542  (100) /10.48.2.169 false
2017-09-07 16:45:43.542  (500) /10.48.2.169 false
2017-09-07 16:45:44.541  (1000) /10.48.2.169 false
2017-09-07 16:45:46.041  (1500) /10.48.2.169 false
2017-09-07 16:45:48.041  (2000) /10.48.2.169 false
2017-09-07 16:45:50.541  (2500) /10.48.2.169 false

所以问题是:InetAddress isReachable 方法是否有最小超时时间?(我怀疑是 1500,但我怀疑,超时时间很长...)

或者也许我只是犯了一个我仍然想念的大错误...

如果这还不够清楚,请告诉我。

感谢您的帮助和想法。

首先你应该注意到 INetAddress.isReachable 的行为在 Java 支持的每个平台上是不一样的。我假设你在 Windows.

上工作

当发生未记录的行为时,您应该始终查看源代码(如果它们可用)。 windows 的 java.net 实现是 OpenJDK 的 here(对于 Oracle JVM 应该非常相似,但我不确定这一点)。

我们在isReachable方法实现中看到的是:

  1. 他们不依赖 ping,因为他们发现 Windows ICMP 协议实施太不可靠
  2. 他们将超时值传递给 NET_Wait 函数

所以 isReachable 方法不执行 ping,我们需要检查 NET_Wait 对超时做了什么,以了解为什么超时不到 1 秒不可能。

这里定义了NET_Wait函数:src/windows/native/java/net/net_util_md.c

它包含一个无限循环,当 select 函数调用期间发生这些事件时该循环会中断:

  • NET_WAIT_CONNECT 套接字文件描述符(套接字连接到远程主机)
  • 超时结束

select 函数记录在手册页中,您可以参考 here。这个手册页告诉我们超时可以 "be rounded up to the system clock granularity, and kernel scheduling delays mean that the blocking interval may overrun by a small amount".

这就是不能保证最小超时值的原因。另外,我认为文档没有说明任何最小超时值,因为实现在 JVM 支持的操作系统上有所不同。

希望这有助于您理解原因。

但是,要实现所需的超时,您可以在单独的任务中测试可达性。您等到任务 returns 结果,或者如果您等待的时间超过超时时间,您将取消任务或忽略其结果。