Workaround for .NET NetworkStream.Length lack of suppport

Go To StackoverFlow.com

0

...basically exactly what the title says. NetworkStream.Length is not implemented. What's an alternative?

I'm trying to make a recursive series of async callbacks that encase calls to NetworkStream.BeginRead(...). To know when I've hit my base case and received all bytes I need to know the length of bytes in the stream. Is there a workaround for this?

Code (the entry point to this code is write after TcpListern.BeginAcceptTcpClient call.:

private void StartRead(IAsyncResult ar)
{
   try
   {
      //Do an initial read:
      AsyncClient client = (AsyncClient)ar.AsyncState;
      int amountRead = 0;
      try
      {
         amountRead = client.ClientStream.EndRead(ar);
      }
      catch (IOException io)
      {
         ProcessDebugLog("Async read complete", io);
         client.ClientStream.Close();
         return;
      }
      string text = Encoding.UTF8.GetString(client.Bytes, 0, amountRead);

      //If TCP segmentation has occurred, more blocks will have
      // to get read in:
      if (client.ClientStream.Position < client.ClientStream.Length /*EXCEPTION HERE*/)
      {
         try
         {
            client.ClientStream.BeginRead(client.Bytes, 0, client.Bytes.Length, StartRead, client);
         }
         catch (IOException io)
         {
            ProcessDebugLog("Async read complete", io);
            client.ClientStream.Close();
         }
      }
      else
      {
         client.ClientStream.Close();
      }
   }
   catch (Exception ex)
   {
      ProcessDebugLog("ERROR - StartRead", ex);
   }
}
2012-04-03 20:05
by kmarks2
Do you control both sides of the connection - Sam Axe 2012-04-03 20:07
Some streams really are streams. You don't know how much water is in that river until the water runs out - Hans Passant 2012-04-03 20:17
@Boo Yes I control both sides - kmarks2 2012-04-03 20:20


3

...basically exactly what the title says. NetworkStream.Length is not implemented. What's an alternative?

You keep reading until the end of the stream. There is no alternative to this - until the stream has been closed, there can always be more data.

If you control the protocol, then if a stream can contain several "messages" you should length-prefix each message. (You can use a delimiter as an alternative, but that's messier.)

Note that you should not decode from binary to text until you've got all the data, or you should use a Decoder which is able to maintain state of "uncompleted" characters - in case your read ends up splitting half way through a character.

2012-04-03 20:07
by Jon Skeet
Thanks. I'll go the delimiter route as the messages can vary widely in length. I control all clients so I can mitigate the mess. I was working off a FileStream example so it didn't immediately occur to me why Length is a problem, but you're completely correct. Upvoted/solved - kmarks2 2012-04-03 20:12
@kmarks2: Why would them varying widely in length suggest using a delimiter? If the sending code knows the length before it starts sending that message, using a length-prefix can end up being much cleaner - Jon Skeet 2012-04-03 20:13
Deployed clients would break. Also they all terminate identically, which is something I had neglected. If I have to update the clients I might miss a few causing breaking - kmarks2 2012-04-03 20:28
@kmarks2: But introducing delimiters is a breaking change too, isn't it? Unless you're only ever going to have one message per connection at the moment, in which case you don't need a delimiter anyway.. - Jon Skeet 2012-04-03 20:33
I had neglected to notice that all messages terminate with the same sequence, that is escaped elsewhere in the message - kmarks2 2012-04-03 20:37