天天看点

Android通过Runtime.getRuntime().exec实现Ping和Traceroute命令时readLine阻塞问题解决

在PC上调用cmd,进行一些常用的命令操作,在Android上的是通过Runtime.getRuntime().exec来执行底层Linux下的程序或脚本(bat)。

首先连接上真机,电脑打开CMD,输入adb-shell,确保你要进行的脚本语言是可以执行的。(比如常见的ping命令)

但是深入一下,发现使用ping命令,并附加一些参数,我们设置 -w 5 了,希望5秒钟如果没有ping通,可以有返回,可是像如下常规的操作,貌似ping下的附加参数是不会起作用的,也就是说在cmd下,我希望ping后5秒没有收到包就返回,但是在android下执行就不会有效果:

Process process = null;
		InputStream instream = null;
		BufferedReader bufferReader = null;

		try {
			process = Runtime.getRuntime().exec(command);

			instream = process.getInputStream();
			bufferReader = new BufferedReader(new InputStreamReader(instream, "GBK"));

			String readline;
			while ((readline = bufferReader.readLine()) != null) {
					results.add(readline);
//					Log.i(TAG, "execute command result : " + readline);
			}

			int status = process.waitFor();
			Log.i(TAG, "execute command :" + command + ", status : " + status);

		} catch (IOException e) {
			Log.e(TAG, e.getMessage());
		} catch (InterruptedException e) {
			Log.e(TAG, e.getMessage());
		}
           

这种常规的操作,如果执行一条Ping命令,当在某个 ip下卡住ping不通时,就有问题了,会发现代码一直会阻塞在 br.readLine()的地方,任何办法都不好解决,网上说的把操作放在另外一个Thread里进行,只是解决了process.waiFor()的阻塞问题。其实也解决不了当进行ping不通时readline阻塞的问题,在ping命令的操作下使用readline并不像读取一个文件,当遇到换行时会结束,ping不通,只能一直阻塞着,除非在外部进行close等操作。

结合国内外论坛,终于找到一个办法,我写成了一个方法类,供大家参考(可直接调用):

package com.vixtel.netvista.gdcmcc.utils;

import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import android.util.Log;

/***
 * 执行命令行工具类
 * 
 * @author yangxiaolong 2014-04-30
 * 
 */
public class CommandUtil {

	public static final String TAG = CommandUtil.class.getSimpleName();
	public static final String COMMAND_SH = "sh";
	public static final String COMMAND_LINE_END = "\n";
	public static final String COMMAND_EXIT = "exit\n";
	private static final boolean ISDEBUG = true;

	/**
	 * 执行单条命令
	 * 
	 * @param command
	 * @return
	 */
	public static List<String> execute(String command) {
		return execute(new String[] { command });
	}

	/**
	 * 可执行多行命令(bat)
	 * 
	 * @param commands
	 * @return
	 */
	public static List<String> execute(String[] commands) {
		List<String> results = new ArrayList<String>();
		int status = -1;
		if (commands == null || commands.length == 0) {
			return null;
		}
		debug("execute command start : " + commands);
		Process process = null;
		BufferedReader successReader = null;
		BufferedReader errorReader = null;
		StringBuilder errorMsg = null;

		DataOutputStream dos = null;
		try {
			// TODO
			process = Runtime.getRuntime().exec(COMMAND_SH);
			dos = new DataOutputStream(process.getOutputStream());
			for (String command : commands) {
				if (command == null) {
					continue;
				}
				dos.write(command.getBytes());
				dos.writeBytes(COMMAND_LINE_END);
				dos.flush();
			}
			dos.writeBytes(COMMAND_EXIT);
			dos.flush();

			status = process.waitFor();

			errorMsg = new StringBuilder();
			successReader = new BufferedReader(new InputStreamReader(
					process.getInputStream()));
			errorReader = new BufferedReader(new InputStreamReader(
					process.getErrorStream()));
			String lineStr;
			while ((lineStr = successReader.readLine()) != null) {
				results.add(lineStr);
				debug(" command line item : " + lineStr);
			}
			while ((lineStr = errorReader.readLine()) != null) {
				errorMsg.append(lineStr);
			}

		} catch (IOException e) {
			e.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				if (dos != null) {
					dos.close();
				}
				if (successReader != null) {
					successReader.close();
				}
				if (errorReader != null) {
					errorReader.close();
				}
			} catch (IOException e) {
				e.printStackTrace();
			}

			if (process != null) {
				process.destroy();
			}
		}
		debug(String.format(Locale.CHINA,
				"execute command end,errorMsg:%s,and status %d: ", errorMsg,
				status));
		return results;
	}

	/**
	 * DEBUG LOG
	 * 
	 * @param message
	 */
	private static void debug(String message) {
		if (ISDEBUG) {
			Log.d(TAG, message);
		}
	}

}