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

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

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

Настройка LAN:

  • 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) запускает веб-сервер на порту 80 и доступен только тогда, когда локальная сеть подключена к Интернету.

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

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

Следующий тест выполняется только в том случае, если локальная сеть подключена к Интернету по связано.

@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.
}
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
11
0
8 924
6

Ответы 6

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

Сроки:

  • 1406 мс: testLocalHost()
  • 5280 мс: testLAN()

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

  • testNoDNS()
  • testHaveDNS()

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

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

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

Удачи!

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

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

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

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

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

Другие вопросы по теме