安卓ICMP ping

5

有没有一种方法可以通过ping主机(标准的Android或通过NDK实现),并获取有关响应的详细信息?(时间,TTL,丢失的数据包等) 我在想某些具有此功能的开源应用程序,但找不到任何...

谢谢

2个回答

15
据我所知,发送ICMP ECHO请求需要root权限(即执行此操作的应用程序需要设置为setuid)-而在“原始”Android中目前不可能实现(甚至在Android中使用InetAddress#isReachable()方法也是一个joke,它不按规范工作)。
使用/usr/bin/ping和进程读取ping结果的非常基本的示例,使用AsyncTask:
public class PingActivity extends Activity {
    PingTask mTask;
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
    }

    @Override
    protected void onResume() {
        super.onResume();
        mTask = new PingTask();
        // Ping the host "android.com"
        mTask.execute("android.com");
    }

    @Override
    protected void onPause() {
        super.onPause();
        mTask.stop();
    }

    class PingTask extends AsyncTask<String, Void, Void> {
        PipedOutputStream mPOut;
        PipedInputStream mPIn;
        LineNumberReader mReader;
        Process mProcess;
        TextView mText = (TextView) findViewById(R.id.text);
        @Override
        protected void onPreExecute() {
            mPOut = new PipedOutputStream();
            try {
                mPIn = new PipedInputStream(mPOut);
                mReader = new LineNumberReader(new InputStreamReader(mPIn));
            } catch (IOException e) {
                cancel(true);
            }

        }

        public void stop() {
            Process p = mProcess;
            if (p != null) {
                p.destroy();
            }
            cancel(true);
        }

        @Override
        protected Void doInBackground(String... params) {
            try {
                mProcess = new ProcessBuilder()
                    .command("/system/bin/ping", params[0])
                    .redirectErrorStream(true)
                    .start();

                try {
                    InputStream in = mProcess.getInputStream();
                    OutputStream out = mProcess.getOutputStream();
                    byte[] buffer = new byte[1024];
                    int count;

                    // in -> buffer -> mPOut -> mReader -> 1 line of ping information to parse
                    while ((count = in.read(buffer)) != -1) {
                        mPOut.write(buffer, 0, count);
                        publishProgress();
                    }
                    out.close();
                    in.close();
                    mPOut.close();
                    mPIn.close();
                } finally {
                    mProcess.destroy();
                    mProcess = null;
                }
            } catch (IOException e) {
            }
            return null;
        }
        @Override
        protected void onProgressUpdate(Void... values) {
            try {
                // Is a line ready to read from the "ping" command?
                while (mReader.ready()) {
                    // This just displays the output, you should typically parse it I guess.
                    mText.setText(mReader.readLine());
                }
            } catch (IOException t) {
            }
        }
    }
}

不行。我有未经root的手机,Net Ping应用程序正在按设计工作。 - user582934
2
如果它正在使用java.lang.Process执行ping命令,那么它可能是设置了setuid并且可以在解析输出时提供TTL - 直接从Java中执行不起作用(Process中的示例实际上正在运行ping命令)。 - Jens
你能在没有root权限的情况下使用java.lang.Process执行'ping'命令吗? - user582934
2
是的,它是 setuid,并且将执行需要具有 root 权限的部分。您将不得不解析它生成的连续字符串输入 - 但上面附加的示例显示了如何使用管道输入/输出流在 UI 线程上处理结果,同时在 AsyncTask 中运行命令。 - Jens
向示例添加了一个修复,现在它将正确地停止AsyncTask(糟糕,忘记了Process会忽略中断)。 - Jens
如果PING进程失败,应将Process.exitValue设置为非零。请注意,您应该使用Process.waitFor确保PING已完成。这样可以避免解析文本输出,这很繁琐且易错。 - Rupert Rawnsley

1
我找到了一种在没有root权限的情况下执行ping命令的方法。
首先生成一个'sh'进程,然后在该shell中执行'ping',代码如下:
p = new ProcessBuilder("sh").redirectErrorStream(true).start();

DataOutputStream os = new DataOutputStream(p.getOutputStream());
os.writeBytes("ping -c 10 " + host + '\n');
os.flush();

// Close the terminal
os.writeBytes("exit\n");
os.flush();

// read ping replys
BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line;

while ((line = reader.readLine()) != null) {
    System.out.println(line);
}

在我的HTC设备上,使用CyanogenMod 7.1.0(Android 2.3.7)可以正常工作。


1
如果在ping命令中没有使用-w <#秒>选项,当无法ping通时可能会出现卡顿 - 这只是一个提醒,对于尝试这个命令的人来说很重要。 - Steve Radich-BitShop.com
1
创建一个 shell,然后启动 ping 是一个糟糕的设计。这会涉及更多的解析和更难传递输入。直接启动 ping 更好。 - C. Ross

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接