Tại sao InetAddress.isReachable trả về false, khi tôi có thể ping địa chỉ IP?


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

Tại sao isReachabletrở lại false? Tôi có thể ping IP.



1
nó tương tự. nhưng tôi không thể tìm thấy bất kỳ manh mối nào để giải quyết vấn đề nên tôi đã sắp xếp lại nó ở đây. Cảm ơn bạn đã nhắc nhở!
jiafu

2
Tôi sẽ thử tăng thời gian chờ.
jayunit100

đây là một câu hỏi rất hay, không có đủ số phiếu ủng hộ. Câu hỏi tương tự duy nhất mà tôi tìm thấy đã được gắn thẻ là câu hỏi áo choàng và câu trả lời là không thể kết luận.
jayunit100

3
ai đó có thể cho tôi biết chính xác thìReachable () làm gì không? nó sẽ trả về tôi sai sự thật ngay cả trên localhost ...
Seth Keno

Câu trả lời:


73

Phương thức "isReachable" không đáng để tôi sử dụng trong nhiều trường hợp. Bạn có thể cuộn xuống dưới cùng để xem giải pháp thay thế của tôi để kiểm tra đơn giản nếu bạn đang trực tuyến và có khả năng phân giải các máy chủ bên ngoài (tức là google.com) ... Điều này thường hoạt động trên các máy * NIX.

Vấn đề

Có rất nhiều cuộc bàn tán về điều này:

Phần 1: Một ví dụ có thể lặp lại của vấn đề

Lưu ý rằng trong trường hợp này, nó không thành công.

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

Phần 2: Giải pháp Hackish

Thay vào đó, bạn có thể làm điều này:

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

Tùy chọn -c của ping sẽ cho phép ping chỉ cần cố gắng truy cập máy chủ một lần (trái ngược với ping vô hạn mà chúng ta thường sử dụng ở thiết bị đầu cuối).

Điều này sẽ trả về 0 nếu máy chủ có thể truy cập được . Nếu không, bạn sẽ nhận được "2" làm giá trị trả về.

Đơn giản hơn nhiều - nhưng tất nhiên nó là nền tảng cụ thể. Và có thể có một số đặc quyền nhất định khi sử dụng lệnh này - nhưng tôi thấy nó hoạt động trên máy của tôi.


XIN LƯU Ý rằng: 1) Giải pháp này không phải là chất lượng sản xuất. Nó có một chút hack. Nếu google ngừng hoạt động, hoặc internet của bạn tạm thời chậm, hoặc thậm chí có thể có một số điều thú vị trong cài đặt đặc quyền / hệ thống của bạn, nếu có thể trả về âm tính sai (tức là nó có thể bị lỗi mặc dù có thể truy cập được địa chỉ đầu vào). 2) Lỗi isReachable là một vấn đề còn tồn tại. Một lần nữa - có một số tài nguyên trực tuyến chỉ ra rằng không có cách nào "hoàn hảo" để thực hiện việc này tại thời điểm viết bài này, do cách JVM cố gắng tiếp cận các máy chủ - tôi đoán đó là một nhiệm vụ cụ thể về bản chất, mặc dù đơn giản , vẫn chưa được tóm tắt đầy đủ bởi JVM.


@ jayunit100 không có cách tiếp cận nào hoạt động, isReachabletôi đang gặp lỗi và sử dụng ping tôi không được phép sử dụng icmp? Bạn đã biết cách đối phó với nó bây giờ chưa?
Yuvi

6
@Yuvi Nếu bạn đang sử dụng Windows, các cờ sẽ khác nhau. Thay vì -c bạn muốn -n.
James T Snell

waitFor () mất 10 giây để trả về. Có cách nào để đề cập đến thời gian chờ trong Java 7 không?
Jaydev

@Jaydev, cũng có một tùy chọn quá tải: public boolean waitFor(long timeout, TimeUnit unit)trong java.lang.Process (@since 1.8)
không thể phân chia

Kể từ năm 2020-01, tôi có thể chạy ví dụ về sự cố mà không gặp bất kỳ sự cố nào, nó báo cáo "Đã kết nối" cho một địa chỉ IPv4 và một địa chỉ IPv6. Các lỗi cũng được cố định trong Java 5.0 B22. Có lẽ isReachablelà đáng tin cậy hơn bây giờ ngày.
Lii

54

Tôi đến đây để tìm câu trả lời cho cùng câu hỏi này, nhưng tôi không hài lòng với bất kỳ câu trả lời nào vì tôi đang tìm kiếm một giải pháp độc lập với nền tảng. Đây là mã mà tôi đã viết và độc lập với nền tảng, nhưng yêu cầu thông tin về bất kỳ cổng nào đang mở trên máy khác (mà chúng tôi có hầu hết thời gian).

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
Đây là một giải pháp độc lập nền tảng tuyệt vời, cảm ơn bạn!
ivandov

1
Tôi rất vui vì tôi đã kết thúc ở đây, cách suy nghĩ tốt đẹp Sourabh :)
JustADev

Vì vậy, chỉ để đảm bảo rằng tôi hoàn toàn hiểu: Miễn là không có ngoại lệ, địa chỉ có thể truy cập được?
Timmiej93

1
Điều này giống với những gì InetAddress.isReachable()đã làm, thông qua cổng 7, ngoại trừ cổng thứ hai thông minh hơn về IOExceptionsý nghĩa của các nghĩa khác nhau về khả năng tiếp cận.
Marquis of Lorne

1
Có @EJP Tôi nghĩ sẽ rất tuyệt nếu InetAddress.isReachable()đưa đối số cổng vào thư viện tiêu chuẩn. Tôi tự hỏi tại sao nó không được bao gồm?
Sourabh Bhat

7

Nếu bạn chỉ muốn kiểm tra xem nó có được kết nối với internet hay không, hãy sử dụng phương pháp này, Nó trả về true nếu internet được kết nối, Sẽ tốt hơn nếu bạn sử dụng địa chỉ của trang web bạn đang cố gắng kết nối thông qua chương trình.

     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
Vô ích nếu máy chủ không phải là máy chủ web, đó hoàn toàn không phải là điều kiện được chỉ định trong câu hỏi.
Fran Marzoa

3

Chỉ đề cập đến nó một cách rõ ràng vì các câu trả lời khác không. Phần ping của isReachable () yêu cầu quyền root trên Unix. Và như được chỉ ra bởi bestsss trong 4779367 :

Và nếu bạn hỏi tại sao ping từ bash lại không, thì thực ra nó cũng cần. Làm điều đó ls -l / bin / ping.

Vì sử dụng root không phải là một tùy chọn trong trường hợp của tôi, giải pháp là cho phép truy cập vào cổng 7 trong tường lửa vào máy chủ cụ thể mà tôi quan tâm.


3

Tôi không chắc trạng thái như thế nào khi câu hỏi ban đầu được hỏi vào năm 2012.

Như hiện tại, ping sẽ được thực thi dưới dạng root. Thông qua ủy quyền của tệp thực thi ping, bạn sẽ thấy cờ + s và tiến trình thuộc quyền root, nghĩa là nó sẽ chạy dưới quyền root. chạy ls -liat vào nơi đặt ping và bạn sẽ thấy nó.

Vì vậy, nếu bạn chạy InetAddress.getByName ("www.google.com"). IsReacheable (5000) dưới dạng root, nó sẽ trả về true.

bạn cần ủy quyền thích hợp cho ổ cắm thô, được sử dụng bởi ICMP (giao thức được sử dụng bởi ping)

InetAddress.getByName cũng đáng tin cậy như ping, nhưng bạn cần có quyền thích hợp đối với quy trình để nó chạy bình thường.


0

Tôi đề xuất rằng cách DUY NHẤT đáng tin cậy để kiểm tra kết nối internet là thực sự kết nối VÀ tải xuống một tệp, HOẶC để phân tích cú pháp đầu ra của lệnh gọi ping hệ điều hành thông qua thi hành (). Bạn không thể dựa vào mã thoát để ping và isReachable () là tào lao.

Bạn không thể dựa vào mã thoát ping vì nó trả về 0 nếu lệnh ping thực thi chính xác. Thật không may, ping thực thi chính xác nếu nó không thể đến được máy chủ đích nhưng nhận được "Máy chủ đích không thể truy cập" từ bộ định tuyến ADSL tại nhà của bạn. Đây là loại trả lời được coi là một lần truy cập thành công, do đó thoát mã = ​​0. Phải thêm mặc dù đây là trên hệ thống Windows. Chưa kiểm tra * 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 là số lần thử ping ip (gói tin), nếu bạn có mạng hoặc hệ thống bận, hãy chọn số nping lớn hơn.
wping là thời gian chờ pong từ ip, bạn có thể đặt nó 2000ms
bằng cách sử dụng phương pháp này. u có thể viết như sau:

isReachable(5, 2000, "192.168.7.93");

tiêm lệnh tiềm năng, hãy đảm bảo xác thực đầu vào chuỗi trước khi chạy điều này
spy

cũng có thông báo lỗi "thất bại chung". Điều này cũng giống như các cửa sổ cụ thể. Tôi khá chắc chắn rằng các thông báo lỗi này được bản địa hóa bằng các ngôn ngữ khác nhau, vì vậy không phải là siêu di động.
spy

cái này dành cho hệ thống windows.
Armin Mokri

vâng, tôi đã từng thấy nó trước đây trên windows
spy

0

Hoặc sử dụng cách này:

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 là flappy và đôi khi trả về không thể truy cập cho các địa chỉ mà chúng tôi có thể ping.

Tôi đã thử những cách sau:

ping -c 1 <fqdn>và kiểm tra exit status.

Hoạt động cho tất cả các trường hợp tôi đã thử InetAddress.isReachablenhưng không hoạt động.


-1

Vì bạn có thể ping máy tính, quy trình Java của bạn sẽ chạy với đủ đặc quyền để thực hiện kiểm tra. Có thể là do sử dụng các cổng ở phạm vi thấp hơn. Nếu bạn chạy chương trình java của mình với sudo / superuser, tôi cá là nó hoạt động.


Bạn không cần đặc quyền để kết nối với các cổng ở phạm vi thấp.
Marquis of Lorne
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.