【问题标题】:Read std output from another program从另一个程序读取标准输出
【发布时间】:2013-03-26 17:44:31
【问题描述】:

我有一个程序(服务器)将四行输出打印到控制台,然后开始侦听来自客户端程序的传入连接。

我有另一个程序(测试仪),我想从服务器读取标准输出并对其进行分析。我已经设置了测试程序来启动服务器并得到它的输出如下:

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();
...

我遇到的问题是,当我自己执行服务器时(或者当我在没有重定向输出的情况下使用测试仪执行它时)我可以在控制台上看到所有四行。但是,当我使用上述代码将服务器输出重定向到测试程序时,测试程序会挂在“ReadToEnd”命令上,就好像它正在等待服务器的更多输出一样。

我也尝试过使用“ReadLine”命令并将其放入重复 4 次的 FOR 循环中。当我这样做时,前三行输出被成功拾取,然后它挂在第 4 个“ReadLine”上,并且永远不会检索服务器输出的第 4 行。

最后,我还尝试使用“读取”命令尝试一次获取一个字符,但仍然无法从服务器输出的第 4 行获取任何字符。

关于我在这里缺少什么的任何建议?

更新: 经过大量搜索,我终于确定问题与输出缓冲问题有关。服务器程序(用 C++ 编写)写入cout,似乎在打印到屏幕时会自动刷新,但在将 stdout 重定向到测试程序时不会自动刷新。我可以在服务器程序中添加setvbuf(stdout, NULL, _IONBF, 0); 以使stdout 不被缓冲,但我更愿意找到另一个不涉及更改服务器程序的解决方案。

【问题讨论】:

标签: c# process io


【解决方案1】:

ReadToEnd 将在流结束时返回。这发生在程序关闭时。

您可以尝试使用事件处理程序server.OutputDataReceived 读取数据。这样您将异步接收它,而不会阻塞您的程序。

【讨论】:

  • 我实际上先异步尝试了它(使用server.OutputDataReceived),但它也没有工作。同样的问题——它只拾取了前三行,并且没有显示后面的任何行。那是我转而尝试同步的时候。顺便说一句,我确实想尝试阻止我的程序(即服务器输出一些值,然后测试人员验证写入的内容,然后发送数据以使服务器继续运行)。只是无论我尝试什么,我似乎都无法让测试人员拾取超过三行。
【解决方案2】:

我昨天在尝试解决这个问题时发现了这个问题,所以我想我会用我找到的解决方案来回答它,只是为了后代。

我遇到的问题是 process.WaitForExit 调用在输出流完成读取之前关闭它们。通过在几个Tasks 中运行ReadLine 循环,并在调用WaitForExit 之前在那些上运行Waiting,我设法获得了所有输出(在本例中来自Git 调用)。

希望这对某人有所帮助。

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();

【讨论】:

    猜你喜欢
    • 2011-07-22
    • 1970-01-01
    • 1970-01-01
    • 2011-09-18
    • 2017-11-10
    • 2012-09-25
    • 1970-01-01
    • 2017-02-03
    • 1970-01-01
    相关资源
    最近更新 更多