从java执行C二进制文件并从进程的输出流中读取

时间:2015-02-10 17:31:36

标签: java c linux

好的,所以我试图从java代码中读取c二进制文件的输出,我无法弄清楚通信通道是阻塞还是非阻塞。

设置如下:

  1. 运行java类(A.java

  2. A.java使用B.o运行c二进制文件(Runtime.getRuntime().exec("B.o"))。此时我有Process对象(由Runtime.exec返回)

  3. A.java使用bufferedreader从Process对象的输入流中读取

  4. A.java将从输入流中读取的数据输出到文件(output.txt

  5. B.o二进制文件只使用printf函数调用打印随机行。

    现在,如果我运行上述设置,我会毫无保留地收到B.o发送的所有数据。然后,为了测试(阻塞/非阻塞事物),我在A.java的Process对象的输入流的每次读取之后将B.o更改为睡眠5毫秒。事实证明,现在我没有收到A.java B.o发送的完整数据。这表明正在使用的通信信道是非阻塞的(根据我的理解不足)。

    然后为了确保,我开始查看java的源代码,看看我是否正确。到目前为止我找到了以下内容:

    Runtime.getRuntime().exec(...)的每次通话都会以forkAndExec()中的ProcessImpl_md.c方式结束。在ProcessImpl_md.c中,执行命令,创建进程,并设置PIPES进行通信(使用c中的管道函数调用)。我无法在源代码中找到 PIPES 设置为非阻塞模式的任何位置(如我的代码所示)。我假设 PIPES 默认为阻止。

    我知道这是检查我想检查的内容的一种非常糟糕的方法。在这里,我离开了我的深度,我想,我只是无用地敲打着头。

    任何人都可以指出我正确的方向或告诉我:

    1. 通过java运行时API创建的进程的 PIPES 是阻塞还是非阻塞?

    2. 当我从输入流中读取A.java后,为什么没有收到所有数据? (假设PIPE正在阻止)

    3. 任何非编程方式(即我不必更改java等源代码!)以确定进程的 PIPES 是否阻塞或非阻塞?

    4. 谢谢。

      编辑:(添加代码)

      以下不是实际的(甚至是可编译的)代码,但它显示了我想要做的事情。

      来源" B.o":

      #include <stdio.h>
      void main(int argc, char*argv[]){
          int a = 0;
          for(; a<9000000; a++){
              printf("%s", argv[1]);
          }
      }
      

      &#34; A.java&#34;的来源:

      <java imports>
      public class A{
          public static void main(String[] args) throws Exception{
              Process p = Runtime.getRuntime().exec("./B.o");
              BufferedReader br = new 
                  BufferedReader(new InputStreamReader(p.getInputStream()));
              int a = 0;
              while(br.readLine() != null){
                  a++;
                  Thread.sleep(5);//data missed if this line not commented out
              }
              br.close();
              System.out.println(a);
          }
      }
      

      请检查我的答案。我的无用问题。

2 个答案:

答案 0 :(得分:3)

Java和外部程序之间的通信通道(有三个,从Java到本机,两个回来)在阻塞或非阻塞模式下运行与是否所有数据都将成功传输无直接关系每个人。同样,读取请求之间的延迟与是否所有数据都将成功传输无关,无论您java.lang.Process的特定实现中的阻塞与非阻塞I / O是什么。

实际上,您探测阻塞与非阻塞进程间I / O的努力是徒劳的,因为提供给Java程序的I / O接口基于InputStreamOutputStream,它仅提供阻止 I / O.即使非阻塞I / O涉及某些低级别的实现,我也无法想到您的程序有任何方法可以检测到它。

关于您的具体问题,但是:

  

通过java运行时API创建的进程的PIPES是阻塞还是非阻塞?

它们可能是其中之一,但它们更可能是阻止因为它更好地匹配呈现给Process用户的界面。

  

当我从输入流中读取A.java后,为什么没有收到所有数据? (假设PIPE正在阻止)

我只能推测,但问题可能出在外部程序中。它可能会在输出缓冲区填满时进入休眠状态,并且没有任何事情可以将其唤醒。如果您的Java程序没有向外部程序发送数据,则可能有助于调用myProcess.getOutputStream().close()。无论如何,一旦你写下你要编写的所有内容,关闭该流就是一个好主意。

  

任何非编程方式(即我不必更改java等的源代码!)来确定进程的PIPES是阻塞还是非阻塞?

您可以在strace下运行VM或将本机调试器连接到它,并以这种方式分析VM的行为。如果你的意思是从Java内部做到这一点,那么答案就是响亮的“不”。您的Java程序将在所有情况下都会看到阻止行为,因为InputStreamOutputStream的合同要求它。

答案 1 :(得分:0)

我犯了一个大错,完全偏离了基础。发布这个答案以澄清事情(尽管我想完全删除这个问题)。我想知道从Java代码运行的C二进制文件之间的通信通道是阻塞还是非阻塞。我提到当我从创建的进程(C代码)的输入流中读取后,我的java代码处于休眠状态时,数据丢失了。因此,数据没有丢失。我实际上在Java代码中放了一个计时器,然后终止C二进制文件的进程。由于PIPES是阻塞的,因此在计时器到期之前无法接收所有数据。我错误地解释了这种数据丢失意味着PIPES是非阻塞的。通过在创建的C二进制进程上运行STRACE来确认这一点。写入系统调用没有EAGAIN错误。我的错。但是,非常感谢大家花时间回应。