外部 C プログラムの標準出力および標準エラーの読み取り中に Java IO 入力ストリームがブロックされる
質問
数日前にも同じ質問をここに投稿しました(Java が inputstream を使用して外部プログラムから標準出力を読み取る)、読み取り中のブロックの処理に関する優れたアドバイス (while(is.read()) != -1)) を見つけましたが、まだ問題を解決できません。
この同様の質問に対する回答を読んだ後、
Java InputStream の読み取りをブロックする(特に、Guss が投稿した回答)、
is.read() != -1 条件を使用して入力ストリームをループすることは、プログラムが対話型である場合には機能しないと信じ始めています (つまり、ユーザーから複数の入力を受け取り、後続の入力で追加の出力を提示します)プログラムは、明示的な終了コマンドが指定された場合にのみ終了します)。マルチスレッドについてはあまり詳しくないことは認めますが、必要なのは、ユーザー入力が必要なときに入力ストリーム スレッド (stdout、stderr に 1 つずつ) を即座に一時停止し、入力が完了すると再開するメカニズムだと思います。ブロックを防ぐために設けられています。以下は、示された行でブロックが発生している現在のコードです。
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 は 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) read() を使用せずに入力ストリーム (stdout、stderr) を取り込むプロセスを制御する方法はありますか?それとも私の実装が間違っているだけなのでしょうか?
2) マルチスレッドは、入力ストリームを取り込んで出力を書き込むプロセスを開発するための正しい戦略ですか?
追伸:誰かが同様の問題と解決策を提供できれば、それは私にとって非常に役立ちます。
解決
の代わりに
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
を呼び出します。
他のヒント
- ばかりのときは通話#run()にrunnableで実行されません。で並行して産卵のjava.lang.スレッドを実行するのrun()の実行可能
- るかどうかのストリームのブロックにより双方のストリームです。れた場合、送信者は送信データの受信機を受けていませんのでデータをお持ちのブロック状態です。場合のプロセッサは何か、ストリームが遮られ、産卵の参)スレッド内のプロセッサーの待ちのための新しいデータを割り込みの代替、新規データ配信.
まず、あなたは、スレッドとのRunnableをよく読んでする必要があります。あなたが直接)(Runnable.runを呼び出すことはありません、あなたはそれを行うには、スレッドを開始するスレッドを設定します。
しかし、もっと重要なのは、三つの独立したスレッドの存在は、いくつかの慎重な設計の必要性を意味します。なぜ3スレッド?あなただけの開始2、および主なもの。
私はあなたのアプリケーションのgenerallアイデアはいくつかの出力が到着するのを、待ってそれを解釈し、その結果として、あなたがコントロールしているアプリケーションにコマンドを送信することであると仮定?
だからあなたのメインスレッドは言ってリーダースレッドのいずれかの周りに待機する必要があり、「より良い彼が何をしたいのかをユーザーに尋ね、なるほど!それは興味深いことです。」
言い換えれば、あなたの読者とあなたの作家の間にいくつかの通信メカニズムを必要としています。 これは、Javaのイベントメカニズムを使用して実装される可能性があります。しかし、より多くの読書私は怖います。
これが仁王が生まれた理由ではないでしょうか?
nioのチャンネルについてはあまり詳しくないのですが、 この答え 役立つかもしれません。nio を使用してファイルを読み取る方法を示します。役立つかもしれません。