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

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

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

局域网设置:

  • thisMachine192.168.0.100
  • otherMachine192.168.0.200
  • 没有机器被称为noMachine或具有IP 192.168.0.222 (始终无法访问)
  • 两台机器都在端口8080上运行Apache Tomcat; 所有其他端口都无法访问(包括端口7
  • example.com208.77.188.166 )在端口80上运行Web服务器,只有在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. } 

以下测试仅在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. } 

以下测试仅在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. } 

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

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

如果要测试是否可以连接到Web服务器,还可以根据主机名和端口号创建URL ,并使用它来创建URLConnection,检查connect方法的结果(包括exception)应告诉您是否网络服务器是可以访问的。

不确定这是多么实用。

如何做相当于traceroute(在windows上的tracert),一旦你获得成功,你可以继续。

在企业网络中,我看到ICMP(ping)被管理员阻止但通常,tracert仍然有效。 如果你能找到一个快速的方法去做tracert的工作,那应该可以做到吗?

祝你好运!

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

时序:

  • 1406ms: testLocalHost()
  • 5280ms: testLAN()

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

  • testNoDNS()
  • testHaveDNS()

如果你需要在非常短的时间内对大量的主机执行此操作,我会考虑使用像fping这样的工具 – shell out来执行它并在它返回时解析输出。 fping一次运行大量的并行查询,所以理论上你可以在一分钟内检查几千台主机(我认为限制是4096?)

主机可用性的速率确定步骤不在您自己的代码中,而是在netlag中。 您必须等待主机响应,这可能需要一些时间。 如果您的程序在等待响应时阻塞,则可能是一个问题。 我通过创建每个主机作为对象来解决这个问题,每个主机都有自己的线程方法来检查可用性。 在我自己的情况下,我有40个主机,我跟踪。 我的主程序每20秒循环一次由40个机器对象组成的数组,在每个机器上调用相应的方法来检查可用性。 由于每个机器对象产生自己的线程来执行此操作,因此所有40台机器同时被询问,并且每个机器的响应时间(最多500毫秒)不是问题。