2

コンソールに 4 行の出力を出力し、クライアント プログラムからの着信接続のリッスンを開始する 1 つのプログラム (サーバー) があります。

サーバーから標準出力を読み取って分析する別のプログラム (テスター) があります。サーバーを起動し、次のように出力を取得するテスター プログラムをセットアップしました。

Process server = new Process();
server.StartInfo.FileName = "server.exe";
server.StartInfo.UseShellExecute = false;
server.StartInfo.RedirectStandardInput = true;
server.StartInfo.RedirectStandardOutput = true;
server.StartInfo.RedirectStandardError = true;
server.Start();
StreamReader serverOutput = server.StandardOutput;
string line = serverOutput.ReadToEnd();
...

私が経験している問題は、サーバーを自分で実行すると (またはリダイレクトされた出力なしでテスターで実行すると)、コンソールに 4 行すべてが表示されることです。しかし、上記のコードを使用してサーバー出力をテスター プログラムにリダイレクトすると、テスター プログラムはサーバーからの出力を待っているかのように "ReadToEnd" コマンドでハングします。

また、「ReadLine」コマンドを使用して、これを 4 回繰り返す FOR ループに入れてみました。これを行うと、出力の最初の 3 行が正常に取得され、4 番目の "ReadLine" でハングし、サーバー出力の 4 行目が取得されません。

最後に、「読み取り」コマンドを使用して文字を 1 つずつ取得しようとしましたが、サーバー出力の 4 行目から文字を取得できません。

ここで何が欠けているかについての提案はありますか?

更新: 大量の検索を行った結果、問題が出力バッファリングの問題に関連していると最終的に判断しました。サーバー プログラム (C++ で記述) は に書き込みますcout。これは、画面に出力するときに自動的にフラッシュされるように見えますが、stdout をテスター プログラムにリダイレクトするときに自動的にフラッシュされません。サーバー プログラムに追加setvbuf(stdout, NULL, _IONBF, 0);して stdout をバッファリングしないようにすることはできますが、サーバー プログラムの変更を伴わない別の解決策を見つけたいと思います。

4

2 に答える 2

1

ストリームが終了すると、ReadToEnd が返されます。そして、これはプログラムが閉じたときに起こります。

イベント ハンドラを使用してデータの読み取りを試すことができますserver.OutputDataReceived。そうすれば、プログラムをブロックすることなく、非同期で受け取ることができます。

于 2013-03-26T18:12:21.577 に答える
0

昨日、この問題を解決しようとしているときにこの質問を見つけたので、後世のために、見つけた解決策で答えようと思いました。

私が遭遇した問題は、process.WaitForExit呼び出しが出力ストリームの読み取りが完了する前に閉じていたことです。いくつかのs でReadLineループを実行し、を呼び出す前に ing を実行することで、すべての出力を (この例では Git 呼び出しから) 取得することができました。TaskWaitWaitForExit

これが誰かに役立つことを願っています。

var psi = new ProcessStartInfo(@"C:\Program Files (x86)\Git\bin\git.exe", "push " + remoteUrl + " " + branch)
{
    UseShellExecute = false,
    RedirectStandardOutput = true,
    RedirectStandardError = true
};

var process = new Process
{
    StartInfo = psi
};

Console.WriteLine("Pushing...");

process.Start();

var stdOutTask = Task.Factory.StartNew(() =>
{
    string str;
    while ((str = process.StandardOutput.ReadLine()) != null)
    {
        Console.WriteLine(str);
    }
});
var stdErrorTask = Task.Factory.StartNew(() =>
{
    string str;
    while ((str = process.StandardError.ReadLine()) != null)
    {
        Console.WriteLine(str);
    }
});

stdOutTask.Wait();
stdErrorTask.Wait();
process.WaitForExit();
process.Close();
于 2014-10-31T09:34:48.173 に答える