Какой самый быстрый способ обнаружить недоступный хост в Java? - PullRequest
11 голосов
/ 12 октября 2008

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

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

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

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

Ответы [ 6 ]

5 голосов
/ 14 октября 2008

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

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

1 голос
/ 14 октября 2008

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

0 голосов
/ 29 апреля 2011

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

0 голосов
/ 15 октября 2008

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

0 голосов
/ 12 октября 2008

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

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

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

Удачи!

0 голосов
/ 12 октября 2008

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

Тайминги:

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

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

  • testNoDNS()
  • testHaveDNS()
...