IP adresine ping atabildiğimde InetAddress.isReachable neden yanlış döndürüyor?


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

Neden isReachablegeri dönüyor false? IP'ye ping atabilirim.



1
benzer. ama sorunu çözmek için herhangi bir ipucu bulamadım, bu yüzden burada yeniden düzenledim. Hatırlatmanız için teşekkürler!
jiafu

2
Zaman aşımını artırmayı deneyeceğim.
jayunit100

bu çok iyi bir soru, yeterince olumlu oy yok. Bulduğum tek benzer soru, bir gizlenme sorusu olarak etiketlendi ve cevap sonuçsuz kaldı.
jayunit100

3
birisi bana isReachable () işlevinin tam olarak ne yaptığını söyleyebilir mi? localhost'ta bile beni yanlış döndürüyor ...
Seth Keno

Yanıtlar:


73

"İsReachable" yöntemi birçok durumda benim için kullanma layık olmamıştır. Çevrimiçi olup olmadığınızı ve harici ana bilgisayarları (ör. Google.com) çözüp çözemeyeceğimi test etmek için alternatifimi görmek için aşağıya kaydırabilirsiniz ... Bu genellikle * NIX makinelerinde çalışıyor gibi görünüyor.

Sorun

Bununla ilgili çok fazla konuşma var:

Bölüm 1: Sorunun tekrarlanabilir bir örneği

Bu durumda başarısız olacağını unutmayın.

       //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*

Bölüm 2: Bir Hackish Çözüm

Alternatif olarak bunu yapabilirsiniz:

// 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);

-C ping seçeneği, ping'in sunucuya bir kez ulaşmaya çalışmasına izin verecektir (terminalde kullandığımız sonsuz ping'in aksine).

Ana bilgisayar erişilebilir durumdaysa bu 0 döndürür . Aksi takdirde, dönüş değeri olarak "2" alırsınız.

Çok daha basit - ama elbette platforma özel. Ve bu komutu kullanmak için belirli ayrıcalık uyarıları olabilir - ancak bunun makinelerimde çalıştığını görüyorum.


LÜTFEN Unutmayın: 1) Bu çözüm üretim kalitesi değildir. Biraz hileli. Google çalışmıyorsa veya internetiniz geçici olarak yavaşsa ya da ayrıcalıklarınızda / sistem ayarlarınızda biraz komiklik olsa bile, yanlış negatifler döndürebilirse (yani, giriş adresi erişilebilir olsa bile başarısız olabilir). 2) isReachable hatası, göze çarpan bir konudur. Yine - JVM'nin ana bilgisayarlara ulaşmaya çalışmasından dolayı, bu yazının yazıldığı sırada bunu yapmanın "mükemmel" bir yolunun olmadığını gösteren birkaç çevrimiçi kaynak var - sanırım bu, basit olmasına rağmen, doğası gereği platforma özgü bir görevdir. , henüz JVM tarafından yeterince soyutlanmamıştır.


@ jayunit100 yaklaşımlarından hiçbiri çalışmıyor, ya isReachablebaşarısız oluyorum ve ping kullanıyorum icmp alıyorum izin verilmiyor? Şimdi bununla nasıl başa çıkacağını biliyor musun?
Yuvi

6
@Yuvi Windows kullanıyorsanız, bayraklar farklıdır. -C yerine -n ​​istersiniz.
James T Snell

waitFor () 'un geri dönmesi 10 saniye sürer. Java 7'de zaman aşımından bahsetmenin bir yolu var mı?
Jaydev

@Jaydev, aşırı yüklenmiş bir seçenek de var: public boolean waitFor(long timeout, TimeUnit unit)java.lang.Process'te (@ 1.8'den beri)
bölünmez

2020-01 itibariyle problemin örneğini sorunsuz çalıştırabiliyorum, bir IPv4 ve bir IPv6 adresi için "Bağlandı" raporunu veriyor. Hata da Java 5.0 B22 düzeltilmiştir. Belki isReachablegünümüzde daha güvenilirdir.
Lii

56

Buraya aynı soruya bir cevap almaya geldim, ancak platformdan bağımsız bir çözüm aradığım için cevapların hiçbirinden memnun değildim. İşte yazdığım ve platformdan bağımsız, ancak diğer makinedeki (çoğu zaman sahip olduğumuz) herhangi bir açık bağlantı noktası hakkında bilgi gerektiren kod.

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
Bu harika bir platform bağımsız çözüm, teşekkürler!
ivandov

1
Ben mutlu ben :) Sourabh düşünme, burada güzel bir şekilde sona erdi değilim
JustADev

Yani, tamamen anladığımdan emin olmak için: İstisna olmadığı sürece, adres ulaşılabilir miydi?
Timmiej93

1
Bu, InetAddress.isReachable()7 numaralı bağlantı noktası aracılığıyla halihazırda yapılanla aynıdır, ancak ikincisi, IOExceptionserişilebilirlik açısından çeşitli olası anlamlar konusunda daha akıllıdır .
Marquis of Lorne

1
Evet @EJP InetAddress.isReachable()Standart kitaplığa port argümanını eklemek için aşırı yüklenmiş olsaydı harika olacağını düşünüyorum . Neden dahil edilmediğini merak ediyorum?
Sourabh Bhat

7

Sadece internete bağlı olup olmadığını kontrol etmek istiyorsanız bu yöntemi kullanın, İnternet bağlıysa true döndürür, Program üzerinden bağlanmaya çalıştığınız sitenin adresini kullanmanız tercih edilir.

     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;
    }

3
Sunucunun bir web sunucusu yoksa işe yaramaz, bu soruda belirtilen bir koşul değildir.
Fran Marzoa

4

Diğer cevaplar söylemediği için bundan açıkça bahsetmek. İsReachable () öğesinin ping kısmı, Unix'te root erişimi gerektirir. Ve bestsss tarafından 4779367'de işaret edildiği gibi :

Bash'den ping'in neden olmadığını sorarsanız, aslında buna da ihtiyacı var. Bunu yapın ls -l / bin / ping.

Benim durumumda kök kullanmak bir seçenek olmadığından, çözüm, ilgilendiğim belirli sunucuya güvenlik duvarındaki 7 numaralı bağlantı noktasına erişime izin vermekti.


4

Orijinal soru 2012'de sorulduğunda durumun ne olduğundan emin değilim.

Şu anda olduğu gibi, ping bir kök olarak yürütülecektir. Ping yürütülebilir dosyasının yetkilendirmesi aracılığıyla + s bayrağını ve köke ait olan süreci göreceksiniz, yani kök olarak çalışacaktır. ping'in bulunduğu yerde ls -liat çalıştırın ve görmelisiniz.

Bu nedenle, InetAddress.getByName ("www.google.com"). İsReacheable (5000) 'i root olarak çalıştırırsanız, true döndürmelidir.

ICMP (ping tarafından kullanılan protokol) tarafından kullanılan ham soket için uygun yetkilendirmelere ihtiyacınız var

InetAddress.getByName, ping kadar güvenilirdir, ancak düzgün çalışması için işlemde uygun izinlere ihtiyacınız vardır.


0

Bilgisayara ping atabildiğiniz için, Java işleminiz denetimi gerçekleştirmek için yeterli ayrıcalıklarla çalışmalıdır. Muhtemelen daha düşük aralıktaki bağlantı noktalarının kullanılması nedeniyle. Java programınızı sudo / superuser ile çalıştırırsanız, işe yarayacağına bahse girerim.


Düşük aralıktaki bağlantı noktalarına bağlanmak için ayrıcalığa ihtiyacınız yok .
Marquis of Lorne

0

Bir internet bağlantısını test etmenin YALNIZCA güvenilir yolunun bir dosyayı gerçekten bağlamak VE indirmek VEYA bir OS ping çağrısının çıktısını exec () aracılığıyla ayrıştırmak olduğunu öneririm. Ping için çıkış koduna güvenemezsiniz ve isReachable () saçmalıktır.

Ping komutu doğru bir şekilde yürütülürse, 0 döndürdüğü için bir ping çıkış koduna güvenemezsiniz. Ne yazık ki, hedef ana bilgisayara ulaşamazsa ancak ev ADSL yönlendiricinizden bir "Ulaşılamayan Hedef ana bilgisayar" alırsa ping doğru şekilde yürütülür. Bu, başarılı bir isabet olarak değerlendirilen bir tür cevaptır, bu nedenle çıkış kodu = 0'dır. Bunun bir Windows sisteminde olduğunu eklemelisiniz. * İşaretli değil.


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;
}

Ağınız meşgulse veya sistemler daha büyük numaralar seçtiyse, nping, ip (paketler) ping yapmaya çalışma sayısıdır.
wping, ipten pong bekleme zamanıdır,
bu yöntemi kullanmak için 2000ms ayarlayabilirsiniz, u şunu yazabilirsiniz:

isReachable(5, 2000, "192.168.7.93");

potansiyel komut enjeksiyonu, bunu çalıştırmadan önce dize girişini doğruladığınızdan emin olun
casus

"genel hata" hata mesajı da var. Bu aynı zamanda belirli pencerelere benziyor. Bu hata mesajlarının farklı dillerde yerelleştirildiğinden oldukça eminim, bu yüzden süper taşınabilir değil.
casus

bu Windows sistemleri içindir.
Armin Mokri

evet bunu daha önce pencerelerde görmüştüm
casus

0

Veya bu şekilde kullanarak:

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 flappy ve bazen ping atabileceğimiz adresler için ulaşılamaz olarak dönüyor.

Aşağıdakileri denedim:

ping -c 1 <fqdn>ve kontrol edin exit status.

InetAddress.isReachableÇalışmayan yerlerde denediğim tüm davalar için çalışıyor.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.