Каков самый быстрый способ обнаружить недостижимый хост в Java?

Мне нужна самая быстрая и точная функция boolean isReachable(String host, int port), которая проходит следующие тесты JUnit в приведенных ниже условиях. Значения тайм-аута определяются самим тестом JUnit и могут считаться "недоступными".

Обратите внимание: Все ответы должны быть независимыми от платформы. Это означает, что InetAddress.isReachable(int timeout) не будет работать, поскольку он использует порт 7 для выполнения ping в Windows (ICMP-пинг является недокументированной функцией в Windows), и этот порт заблокирован в этой настройке.

Настройка локальной сети:

  • thisMachine (192.168.0.100)
  • otherMachine (192.168.0.200)
  • no машина называется noMachine или имеет IP 192.168.0.222 (всегда недоступный)
  • обе машины запускают Apache Tomcat на порту 8080; все остальные порты недоступны (включая порт 7)
  • example.com (208.77.188.166) запускает веб-сервер на порту 80 и доступен только при подключении ЛВС к Интернету

Иногда LAN отключается от Интернета, и в этом случае доступны только локальные компьютеры, вызываемые по 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 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 отключен из Интернета.

@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 подключен к Интернету.

@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.
}

Ответ 1

Во-первых, вам нужно признать, что у вас есть потенциально противоречивые требования; Сокеты IP не детерминированы во времени. Самое быстрое, что вы когда-либо обнаружите недостижимость, - это время, прошедшее с вашего истекшего таймаута. Вы можете быстрее обнаруживать достижимость.

Предполагая, что достижимость /isReachable является вашей реальной целью, вы должны просто использовать простой неблокирующий сокет IO, как показано в Java Ping симулятор, пример подключается к службе времени, но будет работать одинаково хорошо на 8080.

Ответ 2

Если вы хотите проверить, можете ли вы подключиться к веб-серверу, вы также можете создать URL на основе имени хоста и номер порта и использовать это для создания URLConnection проверки результата (включая исключения) метод подключения должен сообщить вам, доступен ли веб-сервер.

Ответ 3

Мое последнее решение зависит от TimedSocket (исходного кода) с тайм-аутом 3000 мс при выполнении подключения.

Тайминги:

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

Не может даже заставить их работать правильно:

  • testNoDNS()
  • testHaveDNS()

Ответ 4

Не знаю, насколько это практично.

Как сделать эквивалент traceroute (tracert on windows), и как только вы добьетесь успеха, вы можете продолжить.

В корпоративных сетях я видел, что ICMP (ping) блокируется администраторами, НО обычно, tracert все еще работает. Если вы можете найти быстрый способ сделать то, что делает tracert, это должно сделать трюк?

Удачи!

Ответ 5

Если вам нужно сделать это с очень большим количеством хостов за очень короткий промежуток времени, я бы подумал об использовании инструмента, такого как fping вместо этого выложить, чтобы выполнить его, и проанализировать вывод, когда он вернется. fping запускает большое количество параллельных запросов сразу, поэтому вы можете теоретически проверить несколько тысяч хостов за минуту (я думаю, что предел равен 4096?)

Ответ 6

Шаг определения скорости для доступности хоста не входит в ваш собственный код, но в netlag. Вы должны дождаться ответа хоста, и это может занять некоторое время. Если ваша программа блокируется в ожидании ответа, это может быть проблемой. Я обошел это, создав каждый хост как объект, каждый со своим собственным поточным методом проверки доступности. В моей собственной ситуации у меня 40 хостов, которые я отслеживаю. Моя основная программа проходит через массив из 40 объектов машины каждые 20 секунд, вызывая соответствующий метод для проверки доступности. Поскольку каждый машинный объект порождает собственный поток, чтобы сделать это, все 40 машин опрошены одновременно, и время отклика (до 500 мс) для каждого не является проблемой.