在Java中检测无法访问的主机的最快方法是什么?

gra*_*r31 11 java sockets networking

我想boolean isReachable(String host, int port)在下面的条件下通过以下JUnit测试的最快和最准确的函数.超时值由JUnit测试本身指定,可能被视为"无法访问".

请注意:所有答案必须与平台无关.这意味着它InetAddress.isReachable(int timeout)无法工作,因为它依赖端口7在Windows 上执行ping操作(ICMP ping是Windows上未记录的功能),并且此端口在此设置中被阻止.

局域网设置:

  • thisMachine(192.168.0.100)
  • otherMachine(192.168.0.200)
  • 没有机器被叫noMachine或有IP 192.168.0.222(总是无法到达)
  • 两台机器都在端口上运行Apache Tomcat 8080; 所有其他端口都无法访问(包括端口7)
  • example.com(208.77.188.166)正在端口上运行Web服务器,80只有在LAN连接到Internet时才可以访问

有时,局域网与Internet断开连接,在这种情况下,只能通过IP地址调用本地计算机(所有其他计算机都无法访问;没有DNS).

所有测试都在运行thisMachine.

@Test(timeout=1600) // ~320ms per call (should be possible to do better)
public void testLocalhost() {
    // We can always reach ourselves.
    assertTrue(isReachable("localhost", 8080));
    assertTrue(isReachable("127.0.0.1", 8080));
    assertTrue(isReachable("thisMachine", 8080)); // Even if there's no DNS!
    assertTrue(isReachable("192.168.0.100", 8080));

    assertFalse(isReachable("localhost", 80)); // Nothing on that port.
}

@Test(timeout=5500) // ~1867ms per call (should be able to do better)
public void testLAN() {
    assertTrue(isReachable("192.168.0.200", 8080)); // Always connected to the LAN.
    assertFalse(isReachable("192.168.0.222", 8080)); // No such a machine.
    assertFalse(isReachable("noMachine", 8080)); // No such machine.
}
Run Code Online (Sandbox Code Playgroud)

以下测试仅在LAN 与Internet 断开连接时运行.

@Test(timeout=5600) // ~1867ms per call (reasonable?)
public void testNoDNS() {
    assertFalse(isReachable("otherMachine", 8080)); // No DNS.
    assertFalse(isReachable("example.com", 80)); // No DNS & no Internet.
    assertFalse(isReachable("208.77.188.166", 80)); // No Internet.
}
Run Code Online (Sandbox Code Playgroud)

以下测试仅在LAN 连接到Internet时运行.

@Test(timeout=5600) // ~1867ms per call (reasonable?)
public void testHaveDNS() {
    assertTrue(isReachable("otherMachine", 8080)); // DNS resolves local names.
    assertTrue(isReachable("example.com", 80)); // DNS available.
    assertTrue(isReachable("208.77.188.166", 80)); // Internet available.
}
Run Code Online (Sandbox Code Playgroud)

Mar*_*mer 5

首先,您需要认识到您有可能存在冲突的要求; IP套接字不是时间确定性的.您可以检测到不可达性的最快速度是在经过超时之后.您只能更快地检测到可达性.

假设可达性/ isReachable是您的真正目标,您应该使用直接的非阻塞套接字IO,如Java Ping模拟器中所示,该示例连接到时间服务但在8080上同样可以正常工作.


gra*_*r31 0

我最近的解决方案取决于在执行连接时使用超时 3000 毫秒的TimedSocket源代码)。

时间:

  • 1406 毫秒:testLocalHost()
  • 5280毫秒:testLAN()

甚至无法让这些正常工作:

  • testNoDNS()
  • testHaveDNS()