How to Ping External IP from Java Android
Asked Answered
M

13

64

I am developing a Ping application for Android 2.2.

I try my code and it works, but only in local IPs, that's my problem I want to do ping to external servers too.

Here is my code:

  private OnClickListener milistener = new OnClickListener() {
    public void onClick(View v) {
        TextView info = (TextView) findViewById(R.id.info);
        EditText edit = (EditText) findViewById(R.id.edit);
        Editable host = edit.getText();
        InetAddress in;
        in = null;
        // Definimos la ip de la cual haremos el ping
        try {
            in = InetAddress.getByName(host.toString());
        } catch (UnknownHostException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        // Definimos un tiempo en el cual ha de responder
        try {
            if (in.isReachable(5000)) {
                info.setText("Responde OK");
            } else {
                info.setText("No responde: Time out");
            }
        } catch (IOException e) {
            // TODO Auto-generated catch block
            info.setText(e.toString());
        }
    }
};

Ping 127.0.0.1 -> OK
Ping 8.8.8.8 (Google DNS) -> Time Out

I put the following line at Manifest XML too:

<uses-permission android:name="android.permission.INTERNET"></uses-permission>

Can anyone suggest me where I'm doing wrong?

Mittiemittimus answered 11/10, 2010 at 10:30 Comment(5)
More information too ^^ Do you test it in the Emulator or on a real device? Do you have internet connection enabled? i.e. on a real device make sure the "mobile network" is activated and that you have an internet connectionLilla
I tested in the Emulator and on a Real Device connected to the internet. Thanks.Mittiemittimus
Did you come right with this issue? I am having the same problem. If you got around this problem, could you also advise me. Regards SanjayAnciently
I am also facing same problem can you please provide solution to this if you found!Handyman
got to this link , i got answer from this, #14577210Valiancy
M
61

I tried following code, which works for me.

private boolean executeCommand(){
        System.out.println("executeCommand");
        Runtime runtime = Runtime.getRuntime();
        try
        {
            Process  mIpAddrProcess = runtime.exec("/system/bin/ping -c 1 8.8.8.8");
            int mExitValue = mIpAddrProcess.waitFor();
            System.out.println(" mExitValue "+mExitValue);
            if(mExitValue==0){
                return true;
            }else{
                return false;
            }
        }
        catch (InterruptedException ignore)
        {
            ignore.printStackTrace();
            System.out.println(" Exception:"+ignore);
        } 
        catch (IOException e) 
        {
            e.printStackTrace();
            System.out.println(" Exception:"+e);
        }
        return false;
    }
Mamiemamma answered 9/5, 2013 at 9:32 Comment(7)
I found this is the only reliable way to check ICMP echo on 4.1.Masbate
Do you need special permissions to run this?Masonmasonic
Can someone please explain this? How does checking for "mExitValue" makes sure that ping was successful?Jeanniejeannine
Checking the exit value of a command is useful because exit 0 generically means the command was successful. Any other value suggests an issue.Theurgy
This leaks memory when put into service and recursively call it! You need to manually close stdin, stdout and stderr file descriptors. runtime.getInputStream().close(); runtime.getOutputStream().close(); runtime.getErrorStream().close(); Use this command to check for pipe leaks: adb shell ls -l /proc/<pid>/fd. Please edit the answer and add stream closes, I crashed at this intended behaviour for days..Hybridism
Correct me if I am wrong, but this will always return true right? Doesn't ping always executes successfully regardless of the connection? It is just the output that changes. I thought. But I could be wrong.Convulsive
@ChadBingham Well, for me ping returns 1 if it was unable to reach the server, so it would appear that the exit code does in fact change, at least on Ubuntu 16.04Solicit
D
25

This is a simple ping I use in one of the projects:

public static class Ping {
    public String net = "NO_CONNECTION";
    public String host = "";
    public String ip = "";
    public int dns = Integer.MAX_VALUE;
    public int cnt = Integer.MAX_VALUE;
}

public static Ping ping(URL url, Context ctx) {
    Ping r = new Ping();
    if (isNetworkConnected(ctx)) {
        r.net = getNetworkType(ctx);
        try {
            String hostAddress;
            long start = System.currentTimeMillis();
            hostAddress = InetAddress.getByName(url.getHost()).getHostAddress();
            long dnsResolved = System.currentTimeMillis();
            Socket socket = new Socket(hostAddress, url.getPort());
            socket.close();
            long probeFinish = System.currentTimeMillis();
            r.dns = (int) (dnsResolved - start);
            r.cnt = (int) (probeFinish - dnsResolved);
            r.host = url.getHost();
            r.ip = hostAddress;
        }
        catch (Exception ex) {
            Timber.e("Unable to ping");
        }
    }
    return r;
}

public static boolean isNetworkConnected(Context context) {
    ConnectivityManager cm =
            (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
    NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
    return activeNetwork != null && activeNetwork.isConnectedOrConnecting();
}

@Nullable
public static String getNetworkType(Context context) {
    ConnectivityManager cm =
            (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
    NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
    if (activeNetwork != null) {
        return activeNetwork.getTypeName();
    }
    return null;
}

Usage: ping(new URL("https://www.google.com:443/"), this);

Result: {"cnt":100,"dns":109,"host":"www.google.com","ip":"212.188.10.114","net":"WIFI"}

Detrude answered 16/6, 2016 at 19:40 Comment(2)
This pings a specific port while the other solutions use the ICMP ping (not port specific). So this is an interesting alternative. I guess, root permissions are not required?Directrix
Root access is not required but <uses-permission android:name="android.permission.INTERNET" />should be in the manifest.Detrude
B
11

Run the ping utility in Android's command and parse output (assuming you have root permissions)

See the following Java code snippet:

executeCmd("ping -c 1 -w 1 google.com", false);

public static String executeCmd(String cmd, boolean sudo){
    try {

        Process p;
        if(!sudo)
            p= Runtime.getRuntime().exec(cmd);
        else{
            p= Runtime.getRuntime().exec(new String[]{"su", "-c", cmd});
        }
        BufferedReader stdInput = new BufferedReader(new InputStreamReader(p.getInputStream()));

        String s;
        String res = "";
        while ((s = stdInput.readLine()) != null) {
            res += s + "\n";
        }
        p.destroy();
        return res;
    } catch (Exception e) {
        e.printStackTrace();
    }
    return "";

}
Blasphemy answered 17/7, 2012 at 15:37 Comment(1)
I'm doing ping -c 10 (10 pings averaged) Would it be possible to display line by line? I tried having it append s to a TextView where it would normally append s to res but that didn't work.Repro
I
9

In my case ping works from device but not from the emulator. I found this documentation: http://developer.android.com/guide/developing/devices/emulator.html#emulatornetworking

On the topic of "Local Networking Limitations" it says:

"Depending on the environment, the emulator may not be able to support other protocols (such as ICMP, used for "ping") might not be supported. Currently, the emulator does not support IGMP or multicast."

Further information: http://groups.google.com/group/android-developers/browse_thread/thread/8657506be6819297

this is a known limitation of the QEMU user-mode network stack. Quoting from the original doc: Note that ping is not supported reliably to the internet as it would require root privileges. It means you can only ping the local router (10.0.2.2).

Irmine answered 29/1, 2012 at 0:29 Comment(0)
C
5

Ping for the google server or any other server

public boolean isConecctedToInternet() {

    Runtime runtime = Runtime.getRuntime();
    try {
        Process ipProcess = runtime.exec("/system/bin/ping -c 1 8.8.8.8");
        int     exitValue = ipProcess.waitFor();
        return (exitValue == 0);
    } catch (IOException e)          { e.printStackTrace(); }
    catch (InterruptedException e) { e.printStackTrace(); }
    return false;
}
Chondriosome answered 21/4, 2016 at 19:34 Comment(3)
From Which version of android this code will work? Will it work on android 4.1+Hurd
This is not an universal solution, because it relies on external utility.Macrophage
keep in mind that the ping binary is not necessarily going to exist on every device. It's up to the manufacturer to include it and not everyone does.Boyett
B
4

I implemented "ping" in pure Android Java and hosted it on gitlab. It does the same thing as the ping executable, but is much easier to configure. It's has a couple useful features like being able to bind to a given Network.

https://github.com/dburckh/AndroidPing

Babcock answered 11/3, 2020 at 23:25 Comment(0)
V
2

This is what I implemented myself, which returns the average latency:

/*
Returns the latency to a given server in mili-seconds by issuing a ping command.
system will issue NUMBER_OF_PACKTETS ICMP Echo Request packet each having size of 56 bytes
every second, and returns the avg latency of them.
Returns 0 when there is no connection
 */
public double getLatency(String ipAddress){
    String pingCommand = "/system/bin/ping -c " + NUMBER_OF_PACKTETS + " " + ipAddress;
    String inputLine = "";
    double avgRtt = 0;

    try {
        // execute the command on the environment interface
        Process process = Runtime.getRuntime().exec(pingCommand);
        // gets the input stream to get the output of the executed command
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream()));

        inputLine = bufferedReader.readLine();
        while ((inputLine != null)) {
            if (inputLine.length() > 0 && inputLine.contains("avg")) {  // when we get to the last line of executed ping command
                break;
            }
            inputLine = bufferedReader.readLine();
        }
    }
    catch (IOException e){
        Log.v(DEBUG_TAG, "getLatency: EXCEPTION");
        e.printStackTrace();
    }

    // Extracting the average round trip time from the inputLine string
    String afterEqual = inputLine.substring(inputLine.indexOf("="), inputLine.length()).trim();
    String afterFirstSlash = afterEqual.substring(afterEqual.indexOf('/') + 1, afterEqual.length()).trim();
    String strAvgRtt = afterFirstSlash.substring(0, afterFirstSlash.indexOf('/'));
    avgRtt = Double.valueOf(strAvgRtt);

    return avgRtt;
}
Vasta answered 20/1, 2016 at 22:53 Comment(0)
T
1

Maybe ICMP packets are blocked by your (mobile) provider. If this code doesn't work on the emulator try to sniff via wireshark or any other sniffer and have a look whats up on the wire when you fire the isReachable() method.

You may also find some info in your device log.

Tachymetry answered 11/10, 2010 at 11:1 Comment(7)
I have tested in a Android 2.2 Tablet connected via Wifi i dont use any Momile Provider. Thanks.Mittiemittimus
Then your next step should be to sniff the traffic (not) generated by your device. There are many things which could went wrong here...Tachymetry
It's unlikely that it's cause by blocked ICMP, as the Android documentation says that InetAddress.isReachable first tries to ping via ICMP if that fails it tries to ping on TCP port 7 (Echo)Lilla
According to android.git.kernel.org/?p=platform/libcore.git;a=blob;f=luni/… ICMP will not be used if you don't specify an interface. isReachable only uses the TCP Echo stuff, seems to be some strange behavior or a firewalling problem or something else... Are you sure you are able to access the internet from your application? Ever tried to recieve a file via HTTP?Tachymetry
how can I test that my app can access to the internet??Mittiemittimus
Seems that the "isReachableByMultiThread" doesn't even try ICMP at the moment. Comment in code: "Spec violation! This implementation doesn't attempt an ICMP; it skips right to TCP echo." - Shame...Sibilate
@Andrioid, for raw socket (ICMP) you need root to do it, it's the same in java. the ping command both on *nix/windows actually runs w/ root/admin priviligesNeri
D
1

Here is simple code to get latency in kotlin: less if, using ip:String as input, using regex to split format, using avg for latency in ms

    var avg = LATENCY_ERROR
    val process = Runtime.getRuntime().exec("/system/bin/ping -c 1 $ip")
    BufferedReader(InputStreamReader(process.inputStream)).forEachLine {
        // it: "PING 194.194.194.194 (194.194.194.194) 56(84) bytes of data."
        // it: "rtt min/avg/max/mdev = 326.137/326.137/326.137/0.000 ms"
        if (it.contains("rtt ")) {
            avg = Regex("\\d+\\.\\d+").findAll(it).toList()[1].value.toFloat().roundToInt()
        }
    }
Disremember answered 1/8, 2022 at 10:40 Comment(1)
Nice and simple. But don't forget to add <uses-permission android:name="android.permission.INTERNET" /> to your manifest!Allain
B
0

To get the boolean value for the hit on the ip

public Boolean getInetAddressByName(String name)
    {
        AsyncTask<String, Void, Boolean> task = new AsyncTask<String, Void, Boolean>()
        {

            @Override
            protected Boolean doInBackground(String... params) {
                try
                {
                    return InetAddress.getByName(params[0]).isReachable(2000);
                }
                catch (Exception e)
                {
                    return null;
                }
            }
        };
        try {
            return task.execute(name).get();
        }
        catch (InterruptedException e) {
            return null;
        }
        catch (ExecutionException e) {
            return null;
        }

    }
Brackish answered 26/12, 2019 at 12:4 Comment(0)
Z
0

2024 update for anyone interested in ICMP ping/echo for Android

icmp4a library (my library) is much better and effective alternative to invoking ping command via Runtime process builder.

Example:

  1. Get the library
implementation "com.marsounjan:icmp4a:1.0.0"
  1. Single ICMP Ping
val icmp = Icmp4a()
val host = "google.com"
try {
  val status = icmp.ping( host = "8.8.8.8")
  val result = status.result
  when (result) {
    is Icmp.PingResult.Success -> Log.d("ICMP", "$host(${status.ip.hostAddress}) ${result.packetSize} bytes - ${result.ms} ms")
    is Icmp.PingResult.Failed -> Log.d("ICMP", "$host(${status.ip.hostAddress}) Failed: ${result.message}")
  }
} catch (error: Icmp.Error.UnknownHost) {
  Log.d("ICMP", "Unknown host $host")
}

Logcat output

2024-01-26 16:22:48.515 ICMP D  google.com(8.8.8.8) 64 bytes - 12 ms
  1. Multiple ICMP Pings with specified interval
val icmp = Icmp4a()
val host = "google.com"
try {
  icmp.pingInterval(
      "8.8.8.8",
      count = 5,
      intervalMillis = 1000
  )
    .onEach { status ->
        val result = status.result
        when (result) {
          is Icmp.PingResult.Success -> Log.d("ICMP", "$host(${status.ip.hostAddress}) ${result.packetSize} bytes - ${result.ms} ms")
          is Icmp.PingResult.Failed -> Log.d("ICMP", "$host(${status.ip.hostAddress}) Failed: ${result.message}")
        }
    }
      .launchIn(viewModelScope)
} catch (error: Icmp.Error.UnknownHost) {
  Log.d("ICMP", "Unknown host $host")
}

Logcat output

2024-01-26 16:29:16.633 ICMP D  google.com(8.8.8.8) 64 bytes - 15 ms
2024-01-26 16:29:17.577 ICMP D  google.com(8.8.8.8) 64 bytes - 17 ms
2024-01-26 16:29:18.598 ICMP D  google.com(8.8.8.8) 64 bytes - 17 ms
2024-01-26 16:29:19.614 ICMP D  google.com(8.8.8.8) 64 bytes - 15 ms
2024-01-26 16:29:20.630 ICMP D  google.com(8.8.8.8) 64 bytes - 13 ms
Zuckerman answered 29/1 at 13:27 Comment(0)
C
-2

Use this Code: this method works on 4.3+ and also for below versions too.

   try {

         Process process = null;

        if(Build.VERSION.SDK_INT <= 16) {
            // shiny APIS 
               process = Runtime.getRuntime().exec(
                    "/system/bin/ping -w 1 -c 1 " + url);


        } 
        else 
        {

                   process = new ProcessBuilder()
                 .command("/system/bin/ping", url)
                 .redirectErrorStream(true)
                 .start();

            }



        BufferedReader reader = new BufferedReader(new InputStreamReader(
                process.getInputStream()));

        StringBuffer output = new StringBuffer();
        String temp;

        while ( (temp = reader.readLine()) != null)//.read(buffer)) > 0)
        {
            output.append(temp);
            count++;
        }

        reader.close();


        if(count > 0)
            str = output.toString();

        process.destroy();
     } catch (IOException e) {
         e.printStackTrace();
    }

    Log.i("PING Count", ""+count);
    Log.i("PING String", str);
Crumpled answered 12/2, 2014 at 7:13 Comment(0)
S
-2

Pink ip Address

  public static int pingHost(String host, int timeout) throws IOException,
        InterruptedException {
    Runtime runtime = Runtime.getRuntime();
    timeout /= 1000;
    String cmd = "ping -c 1 -W " + timeout + " " + host;
    Process proc = runtime.exec(cmd);
    Log.d(TAG, cmd);
    proc.waitFor();
    int exit = proc.exitValue();
    return exit;
}
   Ping a host and return an int value of 0 or 1 or 2 0=success, 1=fail,
   * 2=error
Sardius answered 5/12, 2019 at 8:31 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.