title: .NET NetworkStream Read slowness
body: <p>I've got some network code to process an arbitary TCP connection. </p>
  
  <p>It all seems to work as expected but seems slow. When i've profiled the code the it seems to spend a good 600 ms in NetworkStream.Read() and I'm wondering how to improve it. I've fiddled with the buffer sizes and alternated between a massive buffer to read all of the data in one go or a small one which should concatenate the data into a StringBuilder. Currently the client i'm using is a web-browser but this code is generic and it may well not be HTTP data that is being sent to it. Any ideas?</p>
  
  <p>My code is this:</p>
  
  <pre><code>    public void StartListening()
      {
          try
          {
              lock (oSyncRoot)
              {
                  oTCPListener = new TcpListener(oIPaddress, nPort);
  
                  // fire up the server
                  oTCPListener.Start();
  
                  // set listening bit
                  bIsListening = true;
              }
  
              // Enter the listening loop.
              do
              {
                  // Wait for connection
                  TcpClient newClient = oTCPListener.AcceptTcpClient();
  
                  // queue a request to take care of the client
                  oThreadPool.QueueUserWorkItem(new WaitCallback(ProcessConnection), newClient);
              }
              while (bIsListening);
          }
          catch (SocketException se)
          {
              Logger.Write(new TCPLogEntry("SocketException: " + se.ToString()));
          }
          finally
          {
              // shut it down
              StopListening();
          }
      }
  
      private void ProcessConnection(object oClient)
      {
  
          TcpClient oTCPClient = (TcpClient)oClient;
          try
          {
              byte[] abBuffer = new byte[1024];
              StringBuilder sbReceivedData = new StringBuilder();
  
              using (NetworkStream oNetworkStream = oTCPClient.GetStream())
              {
                  // set initial read timeout to nInitialTimeoutMS to allow for connection
                  oNetworkStream.ReadTimeout = nInitialTimeoutMS;
  
                  int nBytesRead = 0;
  
                  do
                  {
                      try
                      {
                          bool bDataAvailable = oNetworkStream.DataAvailable;
  
                          while (!bDataAvailable)
                          {
                             Thread.Sleep(5);
                             bDataAvailable = oNetworkStream.DataAvailable;
                          }
  
                          nBytesRead = oNetworkStream.Read(abBuffer, 0, abBuffer.Length);
  
                          if (nBytesRead &gt; 0)
                          {
                              // Translate data bytes to an ASCII string and append
                              sbReceivedData.Append(Encoding.UTF8.GetString(abBuffer, 0, nBytesRead));
                              // decrease read timeout to nReadTimeoutMS second now that data is coming in
                              oNetworkStream.ReadTimeout = nReadTimeoutMS;
  
                          }
                      }
                      catch (IOException)
                      {
                          // read timed out, all data has been retrieved
                          nBytesRead = 0;
                      }
                  }
                  while (nBytesRead &gt; 0);
  
                  //send the data to the callback and get the response back
                  byte[] abResponse = oClientHandlerDelegate(sbReceivedData.ToString(), oTCPClient);
                  if (abResponse != null)
                  {
                      oNetworkStream.Write(abResponse, 0, abResponse.Length);
                      oNetworkStream.Flush();
                  }
              }
          }
          catch (Exception e)
          {
              Logger.Write(new TCPLogEntry("Caught Exception " + e.StackTrace));
          }
          finally
          {
              // stop talking to client
              if (oTCPClient != null)
              {
                  oTCPClient.Close();
              }
          }
      }
  </code></pre>
  
  <p>Edit: I get roughly the same figures on two entirely seperate machines (my XP development machine and a 2003 box in a colo). I've put some timing into the code around the relevant parts (using System.Diagnostic.StopWatch) and dump it to a log:</p>
  
  <pre>
  7/6/2009 3:44:50 PM : Debug : While DataAvailable took 0 ms
  7/6/2009 3:44:50 PM : Debug : Read took 531 ms
  7/6/2009 3:44:50 PM : Debug : ProcessConnection took 577 ms
  </pre>