2

I have one program (a server) which prints four lines of output to the console, and then begins listening for an incoming connection from a client program.

I have another program (a tester) where I want to read the standard output from the server and analyze it. I have setup the tester program to start the server and get its output as follows:

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

The problem I am experiencing is that when I execute the server myself (or when I execute it with the tester without redirected output) I can see all four lines on the console. However, when I use the above code to redirect the server output into the tester program, the tester program hangs on the "ReadToEnd" command as if it is waiting for more output from the server.

I have also tried using the "ReadLine" command and putting this into a FOR loop which repeats 4 times. When I do this the first three lines of output are picked up successfully, and then it hangs on the 4th "ReadLine" and never retrieves the 4th line of server output.

Finally, I have also tried using the "Read" command to try getting the characters one at a time, and still I cannot get any characters from the 4th line of server output.

Any suggestions as to what I am missing here?

Update: After a massive amount of searching, I have finally determined that the problem is related to an issue with output buffering. The server program (written in C++) writes to cout, which seems to be automatically flushed when printing to the screen, but not automatically flushed when redirecting stdout into the tester program. I can add setvbuf(stdout, NULL, _IONBF, 0); to the server program to make stdout not be buffered, but I would prefer to find another solution which does not involve changing the server program.

2 Answers2

1

ReadToEnd would return when stream ends. And this happens when program closes.

You can try reading data using event handler server.OutputDataReceived. That way you will receive it asynchronously, without blocking your program.

alex
  • 12,464
  • 3
  • 46
  • 67
  • I actually tried it asynchronously first (using `server.OutputDataReceived`), but it didn't work either. Same issue -- it only picked up the first three lines and didn't ever show any lines which came after. That's when I switched to try synchronous. Incidentally, I actually did want to try to block my program (i.e. server outputs some values, then the tester verifies what was written and then sends data to make the server move on). It's just that no matter what I tried I can't seem to ever get the tester to pick up more than three lines. – user2212659 Mar 26 '13 at 20:34
0

I found this question yesterday while trying to solve this problem, so I thought I'd answer it with the solution I found, just for posterity.

The issue I was encountering was the the process.WaitForExit call was closing the output streams before they'd finished being read. By running the ReadLine loops in a couple of Tasks, and Waiting on those before calling WaitForExit, I managed to get all the output (from a Git call, in this instance).

Hope this helps somebody.

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();
Mark Rendle
  • 9,274
  • 1
  • 32
  • 58