title: Read redirected standard output interactively while the process is running
body: <p>I'm working on a remote shell-like thing for Windows in C#. I have a NetworkStream setup, and a Process wrapper for a instance of the command interpreter. The problem is, I can't read from Standard Output and Standard Error without something messing up. My code for the remote portion is like so:</p>
  
  <pre><code>using System;
  using System.Collections.Generic;
  using System.ComponentModel;
  using System.Diagnostics;
  using System.IO;
  using System.Linq;
  using System.Net;
  using System.Net.Sockets;
  using System.Text;
  using System.Threading;
  using System.Threading.Tasks;
  
  namespace Matt_Damon_Remote_Shell
  {
      class RemoteEnd
      {
          public System.Diagnostics.Process commandHost
          {
              get;
              set;
          }
  
          TcpListener listener;
          TcpClient client;
  
          NetworkStream netStream;
          StreamReader netStreamReader;
          StreamWriter netStreamWriter;
  
          StreamReader outputReader;
          StreamReader errorReader;
  
  
          public RemoteEnd()
          {
              initStream();
              initProcess();
          }
  
          public void receive()
          {
              while (true)
              {
                  netStreamWriter.Write(readOutput());
                  netStreamWriter.Write(readError());
                  netStreamWriter.Flush();
                  string next = getNextCommand();
                  Console.WriteLine("Remote received: " + next);
                  runCommand(next);
              }
  
          }
  
          private void initStream()
          {
              listener = new TcpListener(IPAddress.Parse("127.0.0.1"), 666);
              waitForConnect();
              netStream = client.GetStream();
              netStreamReader = new StreamReader(netStream);
              netStreamWriter = new StreamWriter(netStream);
          }
  
          private void waitForConnect()
          {
              try
              {
                  listener.Start();
              }
              catch (SocketException e)
              {
                  Console.WriteLine(e.ToString());
              }
              client = listener.AcceptTcpClient();
          }
  
          private void initProcess()
          {
              commandHost = new System.Diagnostics.Process();
              //Init process
              commandHost.StartInfo.RedirectStandardInput = true;
              commandHost.StartInfo.RedirectStandardOutput = true;
              commandHost.StartInfo.RedirectStandardError = true;
              commandHost.StartInfo.UseShellExecute = false;
              commandHost.StartInfo.CreateNoWindow = true;
              commandHost.StartInfo.FileName = "cmd.exe";
              commandHost.Start();
              outputReader = new StreamReader(commandHost.StandardOutput.BaseStream);
              errorReader = new StreamReader(commandHost.StandardError.BaseStream);
          }
  
          private string readOutput()
          {
             //Various implementations described below
          }
  
          private string readError()
          {
              //Various implementations described below
          }
  
          private void runCommand(string command)
          {
              if (command == "exit") //this handles the exit function, which doesn't work somehow
              {
                  commandHost.Kill(); 
                  return;
              }
              commandHost.StandardInput.WriteLine(command);
          }
  
          private string getNextCommand()
          {
              if (netStream.CanRead)
              {
                  return netStreamReader.ReadLine();
              }
              else
              {
                  return null;
              }
          }
      }
  }
  </code></pre>
  
  <p>First, I tried to grab it asynchronously, but it messed with the sending of the data back. Given enough time, it would send it all back, but I couldn't get it to send everything over the NetworkStream. If I just ran the program, it sent back nothing. If I took the time to add breakpoints and look at the code, it would often send one or two lines back. I couldn't synchronize the event handlers properly, to get the whole thing back. I also tried reading synchronously, but no matter what I tried, be it <code>ReadLine()</code>, <code>ReadBlock()</code>, or <code>Read()</code>, it all blocks my program, and I can't get past the standard cmd startup message. I know there's an end to the streams when I read them, the debugger shows a non-public char buffer with just null-bytes at the end. But, all the methods described above block until, presumably, the process is closed. I can't do that in my situation, as the process has to stay alive to maintain consistent working directories and things like that. Is there a non-blocking way to read synchronously in my situation, or am I going to have to figure out some way for a proper asynchronous read?</p>