Java IO输入流阻塞同时读取标准输出&外部C程序的标准错误

时间:2009-07-09 18:04:40

标签: java java-io

我几天前在这里发布了同样的问题(Java reading standard output from an external program using inputstream),我在阅读时处理了一个块时发现了一些很好的建议(while(is.read())!= -1 )),但我仍然无法解决问题。

在阅读了这个类似问题的答案后,

Java InputStream blocking read (尤其是Guss发布的答案),

我开始相信,如果程序是交互式的,那么使用is.read()!= -1条件循环输入流是不起作用的(即需要来自用户的多个输入并在后续输入时显示其他输出,只有在给出显式退出命令时才退出程序)。我承认我对多线程知之甚少,但我认为我需要的是一种在需要用户输入时立即暂停输入流线程(stdout,stderr各一个)的机制,并在输入后恢复提供以防止阻止。以下是我当前的代码,该代码在指示的行上遇到阻塞:

EGMProcess egm = new EGMProcess(new String[]{directory + "/egm", "-o",
                "CasinoA", "-v", "VendorA", "-s", "localhost:8080/gls/MessageRobot.action ",
                "-E", "glss_env_cert.pem", "-S", "glss_sig_cert.pem", "-C", "glsc_sig_cert.pem",
                "-d", "config", "-L", "config/log.txt", "-H", "GLSA-SampleHost"}, new String[]{"PATH=${PATH}"}, directory);

    egm.execute();

    BufferedReader stdout = new BufferedReader(new InputStreamReader(egm.getInputStream()));
    BufferedReader stderr = new BufferedReader(new InputStreamReader(egm.getErrorStream()));

    EGMStreamGobbler stdoutprocessor = new EGMStreamGobbler(stdout, egm);
    EGMStreamGobbler stderrprocessor = new EGMStreamGobbler(stderr, egm);

    BufferedWriter stdin = new BufferedWriter(new OutputStreamWriter(egm.getOutputStream()));


    stderrprocessor.run(); //<-- the block occurs here!
    stdoutprocessor.run();


    //EGM/Agent test cases


        //check bootstrap menu
        if(!checkSimpleResult("******** EGM Bootstrap Menu **********", egm))
        {
            String stdoutdump = egm.getStdOut();
            egm.cleanup();
            throw new Exception("can't find '******** EGM Bootstrap Menu **********'" +
                "in the stdout" + "\nStandard Output Dump:\n" + stdoutdump);
        }

        //select bootstrap
        stdin.write("1".toCharArray());
        stdin.flush();

        if(!checkSimpleResult("Enter port to receive msgs pushed from server ('0' for no push support)", egm)){
            String stdoutdump = egm.getStdOut();
            egm.cleanup();
            throw new Exception("can't find 'Enter port to receive msgs pushed from server ('0' for no push support)'" +
                    "in the stdout" + "\nStandard Output Dump:\n" + stdoutdump);
        }

...

public class EGMStreamGobbler implements Runnable{

private BufferedReader instream; private EGMProcess egm; public EGMStreamGobbler(BufferedReader isr, EGMProcess aEGM) { instream = isr; egm = aEGM; } public void run() { try{ int c; while((c = instream.read()) != 1) { egm.processStdOutStream((char)c); } } catch(IOException e) { e.printStackTrace(); } }

}

我为代码的长度道歉,但我的问题是,

1)有没有办法控制输入流(stdout,stderr)的过程而不使用read()?或者我只是严厉执行这个?

2)多线程是否是开发输入流和编写输出过程的正确策略?

PS:如果有人能提出解决方案的类似问题,那将对我有所帮助!

4 个答案:

答案 0 :(得分:8)

而不是

stderrprocessor.run(); //<-- the block occurs here!
stdoutprocessor.run();

你需要启动线程:

Thread errThread = new Thread(stderrprocessor);
errThread.setDaemon( true );
errThread.start();

Thread outThread = new Thread(stdoutprocessor);
outThread.setDaemon( true );
outThread.start();

run()只是Runnable中指定的方法。 Thread.start()在新run() Runnable上调用Thread

答案 1 :(得分:2)

  1. 如果你只是在runnable上调用#run(),它将不会并行执行。要并行运行它,你必须生成一个java.lang.Thread,它执行Runnable的#run()。
  2. 流阻塞是否取决于流的两端。如果发送方未发送任何数据或接收方未接收数据,则表示存在阻塞情况。如果处理器必须执行某些操作,当流被阻止时,您需要在处理器中生成(另一个)线程以等待新数据并在流式传输新数据时中断备用进程。

答案 2 :(得分:1)

首先,您需要阅读Thread和Runnable。你不直接调用Runnable.run(),你设置Threads来做那个,然后启动线程。

但更重要的是,三个独立线程的存在意味着需要一些精心设计。为什么3线程?刚刚开始的两个,主要的一个。

我认为您的应用程序的一般想法是等待某些输出到达,解释它并因此向您正在控制的应用程序发送命令?

所以你的主线程需要等待其中一个读者线程说“啊哈!这很有意思,更好地问用户他想做什么。”

换句话说,您需要在读者和作者之间建立一些沟通机制。 这可以使用Java的事件机制来实现。我害怕更多的阅读。

答案 3 :(得分:1)

这不是创建nio的原因吗?

我对nio中的频道了解不多,但this answer可能会有所帮助。它显示了如何使用nio读取文件。可能有用。