¿Por qué InetAddress.isReachable devuelve falso cuando puedo hacer ping a la dirección IP?


96
InetAddress byName = InetAddress.getByName("173.39.161.140");
System.out.println(byName);
System.out.println(byName.isReachable(1000));

¿Por qué isReachablevuelve false? Puedo hacer ping a la IP.



1
es similar. pero no puedo encontrar ninguna pista para resolver el problema, así que lo volví a plantear aquí. ¡Gracias por tu recordatorio!
jiafu

2
Intentaría aumentar el tiempo de espera.
jayunit100

esta es una muy buena pregunta, no hay suficientes votos a favor. La única pregunta similar que encontré fue etiquetada como una pregunta de clojure y la respuesta no fue concluyente.
jayunit100

3
¿Alguien puede decirme qué hace exactamente isReachable ()? me devuelve falso incluso en localhost ...
Seth Keno

Respuestas:


73

El método "isReachable" no ha sido digno de usar para mí en muchos casos. Puede desplazarse hasta la parte inferior para ver mi alternativa para simplemente probar si está en línea y es capaz de resolver hosts externos (es decir, google.com) ... que generalmente parece funcionar en máquinas * NIX.

La cuestión

Hay mucha charla sobre esto:

Parte 1: un ejemplo reproducible del problema

Tenga en cuenta que en este caso, falla.

       //also, this fails for an invalid address, like "www.sjdosgoogle.com1234sd" 
       InetAddress[] addresses = InetAddress.getAllByName("www.google.com");
      for (InetAddress address : addresses) {
        if (address.isReachable(10000))
        {   
           System.out.println("Connected "+ address);
        }
        else
        {
           System.out.println("Failed "+address);
        }
      }
          //output:*Failed www.google.com/74.125.227.114*

Parte 2: una solución hackish

Como alternativa, puede hacer esto:

// in case of Linux change the 'n' to 'c'
    Process p1 = java.lang.Runtime.getRuntime().exec("ping -n 1 www.google.com");
    int returnVal = p1.waitFor();
    boolean reachable = (returnVal==0);

La opción -c de ping permitirá que ping simplemente intente llegar al servidor una vez (a diferencia del ping infinito que estamos acostumbrados a usar en la terminal).

Esto devolverá 0 si el host es accesible . De lo contrario, obtendrá "2" como valor de retorno.

Mucho más simple, pero por supuesto es específico de la plataforma. Y puede haber ciertas advertencias de privilegio para usar este comando, pero encuentro que funciona en mis máquinas.


TENGA EN CUENTA QUE: 1) Esta solución no es de calidad de producción. Es un truco. Si Google está inactivo, o su Internet está temporalmente lento, o tal vez incluso si hay algo de gracia en sus privilegios / configuración del sistema, podría devolver falsos negativos (es decir, podría fallar aunque la dirección de entrada sea accesible). 2) La falla de isReachable es un problema pendiente. Nuevamente, hay varios recursos en línea que indican que no existe una forma "perfecta" de hacer esto en el momento de escribir este artículo, debido a la forma en que la JVM intenta llegar a los hosts, supongo que es una tarea intrínsecamente específica de la plataforma que, aunque simple , aún no ha sido extraído lo suficiente por la JVM.


@ jayunit100 porque ninguno de los enfoques está funcionando, isReachablesi estoy fallando y usando ping, ¿no se permite icmp? ¿Sabes cómo lidiar con eso ahora?
Yuvi

6
@Yuvi Si está usando Windows, las banderas son diferentes. En lugar de -c quieres -n.
James T Snell

waitFor () tarda 10 segundos en volver. ¿Hay alguna forma de mencionar el tiempo de espera en Java 7?
Jaydev

@Jaydev, también hay una opción sobrecargada: public boolean waitFor(long timeout, TimeUnit unit)en java.lang.Process (@since 1.8)
indivisible

A partir de 2020-01, puedo ejecutar el ejemplo del problema sin ningún problema, informa "Conectado" para una dirección IPv4 y una dirección IPv6. El error también se corrigió en Java 5.0 b22. Quizás isReachablesea ​​más confiable hoy en día.
Lii

54

Vine aquí para obtener una respuesta para esta misma pregunta, pero no estaba satisfecho con ninguna de las respuestas porque estaba buscando una solución independiente de la plataforma. Aquí está el código que escribí y es independiente de la plataforma, pero requiere información sobre cualquier puerto abierto en la otra máquina (que tenemos la mayor parte del tiempo).

private static boolean isReachable(String addr, int openPort, int timeOutMillis) {
    // Any Open port on other machine
    // openPort =  22 - ssh, 80 or 443 - webserver, 25 - mailserver etc.
    try {
        try (Socket soc = new Socket()) {
            soc.connect(new InetSocketAddress(addr, openPort), timeOutMillis);
        }
        return true;
    } catch (IOException ex) {
        return false;
    }
}

2
Esta es una gran solución independiente de la plataforma, ¡gracias!
ivandov

1
Estoy feliz de haber terminado aquí, buena forma de pensar Sourabh :)
JustADev

Entonces, solo para asegurarme de que lo entiendo completamente: siempre que no haya una excepción, ¿la dirección fue accesible?
Timmiej93

1
Esto es idéntico a lo que InetAddress.isReachable()ya hace, a través del puerto 7, excepto que este último es más inteligente sobre lo que los diversos posibles IOExceptionssignifican en términos de accesibilidad.
Marqués de Lorne

1
Sí @EJP Creo que sería genial si InetAddress.isReachable()se sobrecargara para incluir el argumento del puerto, en la biblioteca estándar. Me pregunto por qué no estaba incluido.
Sourabh Bhat

7

Si solo desea verificar si está conectado a Internet, use este método. Devuelve verdadero si Internet está conectado. Es preferible si usa la dirección del sitio al que está intentando conectarse a través del programa.

     public static boolean isInternetReachable()
    {
        try {
            //make a URL to a known source
            URL url = new URL("http://www.google.com");

            //open a connection to that source
            HttpURLConnection urlConnect = (HttpURLConnection)url.openConnection();

            //trying to retrieve data from the source. If there
            //is no connection, this line will fail
            Object objData = urlConnect.getContent();

        } catch (Exception e) {              
            e.printStackTrace();
            return false;
        }

        return true;
    }

2
Inútil si el servidor no tiene un servidor web, esa no es una condición especificada en la pregunta en absoluto.
Fran Marzoa

3

Solo mencionándolo explícitamente ya que las otras respuestas no lo hacen. La parte de ping de isReachable () requiere acceso de root en Unix. Y como lo señala bestsss en 4779367 :

Y si pregunta por qué el ping de bash no lo hace, en realidad también lo necesita. Haz eso ls -l / bin / ping.

Dado que usar root no era una opción en mi caso, la solución fue permitir el acceso al puerto 7 en el firewall para el servidor específico que me interesaba.


3

No estoy seguro de cuál era el estado cuando se hizo la pregunta original en 2012.

Tal como está ahora, ping se ejecutará como root. A través de la autorización del ejecutable ping, verá el indicador + s, y el proceso que pertenece a root, lo que significa que se ejecutará como root. ejecute ls -liat donde se encuentra el ping y debería verlo.

Por lo tanto, si ejecuta InetAddress.getByName ("www.google.com"). IsReacheable (5000) como root, debería devolver verdadero.

necesita las autorizaciones adecuadas para el socket sin procesar, que es utilizado por ICMP (el protocolo utilizado por ping)

InetAddress.getByName es tan confiable como ping, pero necesita los permisos adecuados en el proceso para que se ejecute correctamente.


0

Sugeriría que la ÚNICA forma confiable de probar una conexión a Internet es conectarse Y descargar un archivo, O analizar la salida de una llamada de ping del sistema operativo a través de exec (). No puede confiar en el código de salida para hacer ping e isReachable () es una mierda.

No puede confiar en un código de salida de ping, ya que devuelve 0 si el comando ping se ejecuta correctamente. Desafortunadamente, el ping se ejecuta correctamente si no puede alcanzar el host de destino, pero obtiene un "Host de destino inalcanzable" de su enrutador ADSL doméstico. Esta es una especie de respuesta que se trata como un acierto exitoso, por lo tanto, código de salida = 0. Sin embargo, debo agregar que esto es en un sistema Windows. No marcado * nixes.


0
 private boolean isReachable(int nping, int wping, String ipping) throws Exception {

    int nReceived = 0;
    int nLost = 0;

    Runtime runtime = Runtime.getRuntime();
    Process process = runtime.exec("ping -n " + nping + " -w " + wping + " " + ipping);
    Scanner scanner = new Scanner(process.getInputStream());
    process.waitFor();
    ArrayList<String> strings = new ArrayList<>();
    String data = "";
    //
    while (scanner.hasNextLine()) {
        String string = scanner.nextLine();
        data = data + string + "\n";
        strings.add(string);
    }

    if (data.contains("IP address must be specified.")
            || (data.contains("Ping request could not find host " + ipping + ".")
            || data.contains("Please check the name and try again."))) {
        throw new Exception(data);
    } else if (nping > strings.size()) {
        throw new Exception(data);
    }

    int index = 2;

    for (int i = index; i < nping + index; i++) {
        String string = strings.get(i);
        if (string.contains("Destination host unreachable.")) {
            nLost++;
        } else if (string.contains("Request timed out.")) {
            nLost++;
        } else if (string.contains("bytes") && string.contains("time") && string.contains("TTL")) {
            nReceived++;
        } else {
        }
    }

    return nReceived > 0;
}

nping es el número de intentos de hacer ping a ip (paquetes), si tiene una red o sistemas ocupados, elija números de nping más grandes.
wping es el tiempo de espera para pong desde ip, puede configurarlo en 2000ms
para usar este método, puede escribir esto:

isReachable(5, 2000, "192.168.7.93");

posible inyección de comando, asegúrese de validar la entrada de la cadena antes de ejecutar esto
espía

también está el mensaje de error "falla general". Esto también parece específico de Windows. Estoy bastante seguro de que estos mensajes de error están localizados en diferentes idiomas, por lo que no son superportátiles.
espía

esto es para sistemas Windows.
Armin Mokri

sí, lo he visto antes en Windows
espía

0

O usando de esta manera:

public static boolean exists(final String host)
{
   try
   {
      InetAddress.getByName(host);
      return true;
   }
   catch (final UnknownHostException exception)
   {
      exception.printStackTrace();
      // Handler
   }
   return false;
}

0

InetAddress.isReachable es flappy y, a veces, devuelve inalcanzable para direcciones a las que podemos hacer ping.

Intenté lo siguiente:

ping -c 1 <fqdn>y compruebe el exit status.

Funciona para todos los casos que probé donde InetAddress.isReachableno funciona.


-1

Como puede hacer ping a la computadora, su proceso de Java debe ejecutarse con privilegios suficientes para realizar la verificación. Probablemente debido al uso de puertos en el rango inferior. Si ejecuta su programa java con sudo / superuser, apuesto a que funciona.


No necesita privilegios para conectarse a puertos en el rango bajo.
Marqués de Lorne
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.