天天看点

Process子进程和主进程间互传信息--及遇到的问题解决

最近公司新上了一个自动化测试的项目,需要在我们的App里面开启一个进程去调用测试的App,在这工程中,主进程可能随时向子进程发送一些命令,而子进程在测试完成后也要把结果返回给子进程,因为本人以前对Process相当陌生,所以写的过程出现各种问题,而且发生网上的一些解决方法对自己也并不适用,所以就写了这篇文章。
我们先来看一下怎么启动一个子进程。
           

其中ProcessField.COMMAND_SU=”su”;//当成功获取root后可以访问系统文件的进程

ProcessField.COMMAND_SH=”sh”;//未Root获取的进程

Process有三个方法,可以获取到进程里的流,

BufferedReader successResult = null;
    BufferedReader errorResult = null;
    DataOutputStream os = null;
    os = new DataOutputStream(process.getOutputStream());
    successResult = new BufferedReader(new InputStreamReader(process.getInputStream()));
    errorResult = new BufferedReader(new InputStreamReader(process.getErrorStream()));
           

这样就可以获取到Process里的输入流、输出流、和错误流了。

有了这三个流我们就可以和子进程进行数据的发送与接受了。

1、首选往子进程发生信息:

os.writeBytes(COMMAND_EXIT);
    os.flush();
           
上面这两句,就可以向子进程发送消息了,当然os可以写好几种格式的,都可以。
           

2、子进程接受主进程发送过来的消息:

InputStream is=System.in;
if ((length=is.read(buffer))!=-) {
String string=new String(buffer, , length);
}
           

上面语句就可以接受到主进程发过来的信息了,不过要记得开启子线程进行接收,因为is.read()方法是堵塞的,当主进程没有消息发送时,is.read()便一直堵塞在这里了。

is还有一个方法是is.available(),当时system.in时,这个方法代表的含义是,判断is中是否有内容,如果is.available()==0的话证明主进程没有发送消息,根据这个方法的返回值我们可以选择跳过is.read()方法。

3、子进程向主进程发送消息:

只需要这一句就OK了,就发送给主进程了。

4、主进程接收消息:

String s;
                while ((s = successResult.readLine()) != null) {
                    Log.getInstance().debugFun("ShellUtil", s);
                    successMsg.append(s);
                    successMsg.append("\n");
                }
                while ((s = errorResult.readLine()) != null) {
                    errorMsg.append(s);
                }
           

其中successResult和errorResult输入流、错误流;这两个流我们在上面已经创建了,主进程就是通过这两个流来接收子进程发送过来的消息的,包括错误信息。

5、在这因为我们开启了一个子进程,一般都会有需求,要求主进程等待子进程结束,并收到子进程返回信息,这时process提供了下面一个方法:

这个方法就是主进程会一直等待子进程执行完后才会结束,否则主进程一直等待,这个方法返回是一个int指。

6、可能会遇到的问题,堵塞,就是执行之后发现,process.waitfor()这个方法堵塞了,拥有结束不了,我在网上搜了下大部分都是说因为子进程发送消息太多,而Process的输入流和缓冲流的接受内容有限,造成堵塞,解决方法是在process.waitFor()方法调用前,开启一个子线程,来一直让Process的输入流和错误流读取消息。

new Thread(new Runnable() {

                @Override
                public void run() {
                  String s;
                while ((s = successResult.readLine()) != null) {
                    Log.getInstance().debugFun("ShellUtil", s);
                    successMsg.append(s);
                    successMsg.append("\n");
                }
                while ((s = errorResult.readLine()) != null) {
                    errorMsg.append(s);
                }
                }).start();
process.waitFor();
           

但是我这子进程发送给主进程的消息并不多,只是很少的字符串而已,所以这个方法对我根本不管用。

因为这个问题我也是找了半天,在子进程强制把System.in.close()了也不行,强制system.exit()也不行,最后发现问题了。我在主进程这边主动发Process的输出流os.close()关了就可以了。

原理是:Process这边的输出流os如果不关闭的话,子进程那边的输入流就会一直尝试读取,这就造成一直堵塞的结果。

好不容易找到这问题了,子进程和主进程也可以互相传递消息了,但是一个问题来了,我们的需求是服务器会不定的发送给主进程一些消息,然后主进程需要发送给子进程,而因为在开启子进程后,我们调用了:

这个方法,所以一旦子进程开启了,主进程就会等待,那么服务器发送过来的消息,主进程只要等到子进程结束了才能接受到,这样就不行了,我就不能实时向子进程发送消息了。后来我试了一下将process.waitFor()注释掉,然后用一个boolean型变量,来判断子进程是否结束了(因为我这边子进程结束了会发送特定的标志);这时一运行程序发送子进程调不起来了,这证明process.waitFor()这个方法是必须的,不能去掉,那就尝试换个方法取代,经过尝试,使用process.wait(10000)取代process.waitFor()可以实现我想要的效果,具体里面的时间写多少,可看情况而定。

最后我这边使用了一个boolean型的标志位+process.wait(10000)实现了我需要的效果,在process.wait(10000)前面,我开启了一个子线程来一直去读子进程返回的数据,当收到结束标志时,我把boolean型的标志位改变,同时process.destroy()掉,同时还会再开启一个子线程,当主进程接收到服务器发送的消息时,及时使用os写给子进程。

可能不太好,但是我现在只找到了这么一个方法。

总结:

主进程发送和接受消息的三个方法

process.getErrorStream();
process.getOutputStream();
process.getInputStream();
           

子进程接收和发送消息的方法

system.in;
system.out;
           

继续阅读