Mengapa InetAddress.isReachable mengembalikan false, ketika saya bisa melakukan ping ke alamat IP?


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

Mengapa isReachablekembali false? Saya bisa melakukan ping ke IP.



1
itu serupa. tetapi saya tidak dapat menemukan petunjuk apa pun untuk menyelesaikan masalah. Jadi saya menerbitkannya kembali di sini. Terima kasih atas pengingat Anda!
jiafu

2
Saya akan mencoba menambah waktu tunggu.
jayunit100

ini adalah pertanyaan yang sangat bagus, tidak ada cukup suara positif. Satu-satunya pertanyaan serupa yang saya temukan ditandai sebagai pertanyaan clojure dan jawabannya tidak meyakinkan.
jayunit100

3
dapatkah seseorang memberi tahu saya apa sebenarnya isReachable ()? itu mengembalikan saya palsu bahkan di localhost ...
Seth Keno

Jawaban:


73

Metode "isReachable" tidak layak digunakan untuk saya dalam banyak kasus. Anda dapat menggulir ke bawah untuk melihat alternatif saya untuk sekadar menguji jika Anda sedang online dan mampu menyelesaikan host eksternal (yaitu google.com) ... Yang biasanya berfungsi pada mesin * NIX.

Masalah

Ada banyak obrolan tentang ini:

Bagian 1: Contoh masalah yang dapat direproduksi

Perhatikan bahwa dalam kasus ini, gagal.

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

Bagian 2: Solusi Hackish

Sebagai alternatif, Anda dapat melakukan ini:

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

Opsi ping -c akan memungkinkan ping untuk hanya mencoba menjangkau server sekali (berlawanan dengan ping tak terbatas yang biasa kami gunakan di terminal).

Ini akan mengembalikan 0 jika tuan rumah dapat dijangkau . Jika tidak, Anda akan mendapatkan "2" sebagai nilai pengembalian.

Jauh lebih sederhana - tetapi tentu saja ini khusus platform. Dan mungkin ada peringatan hak istimewa tertentu untuk menggunakan perintah ini - tetapi saya merasa perintah ini berfungsi di komputer saya.


HARAP Perhatikan bahwa: 1) Solusi ini bukan kualitas produksi. Ini sedikit hack. Jika google sedang down, atau internet Anda untuk sementara lambat, atau bahkan jika ada beberapa keanehan dalam pengaturan sistem / hak istimewa Anda, jika bisa mengembalikan negatif palsu (yaitu bisa gagal meskipun alamat input dapat dijangkau). 2) Kegagalan isReachable adalah masalah luar biasa. Sekali lagi - ada beberapa sumber daya online yang menunjukkan bahwa tidak ada cara yang "sempurna" untuk melakukan ini pada saat penulisan ini, karena cara JVM mencoba menjangkau host - saya rasa ini adalah tugas khusus platform yang secara intrinsik, meskipun sederhana , belum cukup diabstraksi oleh JVM.


@ jayunit100 karena tidak ada pendekatan yang berfungsi, isReachablesaya gagal dan menggunakan ping saya mendapatkan icmp tidak diizinkan? Apakah Anda tahu bagaimana menghadapinya sekarang?
Yuvi

6
@Yuvi Jika Anda menggunakan Windows, benderanya berbeda. Alih-alih -c Anda menginginkan -n.
James T Snell

waitFor () membutuhkan waktu 10 detik untuk kembali. Apakah ada cara untuk menyebutkan waktu tunggu di Java 7?
Jaydev

@Jaydev, ada opsi kelebihan beban juga: public boolean waitFor(long timeout, TimeUnit unit)di java.lang.Process (@since 1.8)
tak terpisahkan

Mulai 2020-01 saya dapat menjalankan contoh masalah tanpa masalah, ia melaporkan "Tersambung" untuk satu alamat IPv4 dan satu alamat IPv6. The bug juga tetap di Jawa 5.0 b22. Mungkin isReachablesekarang lebih bisa diandalkan.
Lii

54

Saya datang ke sini untuk mendapatkan jawaban untuk pertanyaan yang sama ini, tetapi saya tidak puas dengan jawaban mana pun karena saya mencari solusi platform independen. Berikut adalah kode yang saya tulis dan platform independen, tetapi memerlukan informasi tentang port terbuka apa pun di komputer lain (yang sering kami miliki).

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
Ini adalah solusi independen platform yang hebat, terima kasih!
ivandov

1
Saya senang saya berakhir di sini, cara berpikir yang bagus Sourabh :)
JustADev

Jadi, hanya untuk memastikan saya benar-benar mengerti: Selama tidak ada pengecualian, alamatnya bisa dihubungi?
Timmiej93

1
Ini identik dengan apa yang InetAddress.isReachable()telah dilakukan, melalui port 7, kecuali port 7 lebih cerdas tentang apa arti berbagai kemungkinan IOExceptionsdalam hal jangkauan.
Marquis dari Lorne

1
Ya @EJP Saya pikir akan lebih bagus jika InetAddress.isReachable()kelebihan beban untuk memasukkan argumen port, di perpustakaan standar. Saya bertanya-tanya mengapa itu tidak disertakan?
Sourabh Bhat

7

Jika Anda hanya ingin memeriksa apakah itu terhubung ke internet menggunakan metode ini, Ini mengembalikan true jika internet terhubung, Lebih disukai jika Anda menggunakan alamat situs yang Anda coba sambungkan melalui program.

     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
Tidak berguna jika server tidak memiliki server web, itu sama sekali bukan kondisi yang ditentukan dalam pertanyaan.
Fran Marzoa

3

Hanya menyebutkannya secara eksplisit karena jawaban yang lain tidak. Bagian ping dari isReachable () membutuhkan akses root pada Unix. Dan seperti yang ditunjukkan oleh bestsss di 4779367 :

Dan jika Anda bertanya mengapa ping dari bash tidak, sebenarnya itu juga perlu. Lakukan itu ls -l / bin / ping.

Karena menggunakan root bukanlah pilihan dalam kasus saya, solusinya adalah mengizinkan akses ke port 7 di firewall ke server tertentu yang saya minati.


3

Saya tidak yakin bagaimana keadaannya ketika pertanyaan asli diajukan pada tahun 2012.

Seperti saat ini, ping akan dijalankan sebagai root. Melalui otorisasi ping yang dapat dieksekusi, Anda akan melihat tanda + s, dan proses milik root, yang berarti itu akan berjalan sebagai root. jalankan ls -liat di tempat ping berada dan Anda akan melihatnya.

Jadi, jika Anda menjalankan InetAddress.getByName ("www.google.com"). IsReacheable (5000) sebagai root, ini akan menampilkan true.

Anda memerlukan otorisasi yang tepat untuk soket mentah, yang digunakan oleh ICMP (protokol yang digunakan oleh ping)

InetAddress.getByName sama andalnya dengan ping, tetapi Anda memerlukan izin yang tepat agar prosesnya dapat berjalan dengan baik.


0

Saya menyarankan bahwa SATU-SATUNYA cara yang dapat diandalkan untuk menguji koneksi internet adalah dengan benar-benar menghubungkan DAN mengunduh file, ATAU untuk mengurai output dari panggilan ping OS melalui exec (). Anda tidak dapat mengandalkan kode keluar untuk ping dan isReachable () adalah omong kosong.

Anda tidak dapat mengandalkan kode keluar ping karena mengembalikan 0 jika perintah ping dijalankan dengan benar. Sayangnya, ping dijalankan dengan benar jika tidak dapat menjangkau host target tetapi mendapatkan "Host tujuan tidak dapat dijangkau" dari router ADSL rumah Anda. Ini adalah jenis balasan yang diperlakukan sebagai hit yang berhasil, jadi kode keluar = 0. Perlu ditambahkan meskipun ini ada di sistem Windows. Tidak dicentang * 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 adalah jumlah mencoba untuk melakukan ping ip (paket), jika Anda memiliki jaringan atau sistem yang sibuk pilih nomor nping yang lebih besar.
wping adalah waktu menunggu pong dari ip, Anda dapat mengaturnya 2000ms
untuk menggunakan metode ini Anda dapat menulis ini:

isReachable(5, 2000, "192.168.7.93");

injeksi perintah potensial, pastikan untuk memvalidasi input string sebelum menjalankan ini
spy

ada juga pesan kesalahan "kegagalan umum". Ini juga terlihat seperti jendela khusus. Saya cukup yakin pesan kesalahan ini dilokalkan dalam berbagai bahasa, jadi tidak super portabel.
mata

ini untuk sistem windows.
Armin Mokri

yup saya pernah melihatnya sebelumnya di windows
spy

0

Atau gunakan cara ini:

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 adalah flappy, dan terkadang mengembalikan tidak terjangkau untuk alamat yang dapat kita ping.

Saya mencoba yang berikut ini:

ping -c 1 <fqdn>dan periksa exit status.

Berfungsi untuk semua kasus yang saya coba di mana InetAddress.isReachabletidak berhasil.


-1

Karena Anda dapat melakukan ping ke komputer, proses Java Anda harus berjalan dengan hak yang cukup untuk melakukan pemeriksaan. Mungkin karena penggunaan port di kisaran bawah. Jika Anda menjalankan program java Anda dengan sudo / superuser, saya yakin itu berhasil.


Anda tidak perlu hak istimewa untuk terhubung ke port dalam kisaran rendah.
Marquis dari Lorne
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.