天天看點

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

}