[Okta Webinar] Learn how to a build a cloud-first strategyRegister Now

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 919
  • Last Modified:

Get Length of Network Stream...

I'm trying to figure out how to get the length of a network stream in C#. From
what I've read this is a non-trivial thing to do and I need some help.

Here's the code I'm working on:

      //Unless I know the size of the buffer ahead of time and I cannot
      //this code will freeze up as read is too large. read[] has to be
      //exactly the size of the stream or things lock up inside the call
      //to ReadWholeArray. However in this case I know the stream is
                //1029 bytes. If I init read[1029] things work. But I'll call this
                //again to dump a file from the telnet session and I cannot in
                //any way predict the size of the stream. If I try SizeOf, .Length
                //or anything else it chunders. How can I (at runtime get the
                //byte size of getStream so I can init read[getStream.Size] or
                //or something like that.

      ReadWholeArray(getStream = client.GetStream(), read);
      bytes = getStream.Read(read, 0, read.Length);
      data = Encoding.ASCII.GetString(read);
      System.Diagnostics.Debug.WriteLine(data);

public static void ReadWholeArray (Stream stream, byte[] data)
{
      int offset=0;
      int remaining = Convert.ToInt32(stream.Length);
      while (remaining > 0)
      {
            int read = stream.Read(data, offset, remaining);
            if (read <= 0)
                  throw new EndOfStreamException
                        (String.Format("End of stream reached with {0} bytes left to read", remaining));
            remaining -= read;
            System.Diagnostics.Debug.WriteLine("Read: " + read + " - Remaining: " + remaining);
            offset += read;
      }
}




0
rawinnlnx9
Asked:
rawinnlnx9
  • 7
  • 3
1 Solution
 
j-trobecCommented:
One thing I've done as a work-around for issues like this (for instance, with streams from HttpWebRequests), is to read the entire stream into a MemoryStream:

create a new MemoryStream
wrap it in a BinaryWriter
loop writing bytes from the network stream to the binary writer until the network stream is completely read

Then you can transfer the memory stream, which will have a known length, to an array.  Be sure to set the position of the stream to the first byte, though.

Hope that helps.
0
 
rawinnlnx9Author Commented:
Yeah, this what you  mean right?

For some reason (and I've not the experience yet to know) this code hangs.

public static byte[] ReadFully (Stream stream, int initialLength)
{
    // If we've been passed an unhelpful initial length, just
    // use 32K.
    if (initialLength < 1)
    {
        initialLength = 32768;
    }
   
    byte[] buffer = new byte[initialLength];
    int read=0;
   
    int chunk;
    while ( (chunk = stream.Read(buffer, read, buffer.Length-read)) > 0)
    {
        read += chunk;
       
        // If we've reached the end of our buffer, check to see if there's
        // any more information
        if (read == buffer.Length)
        {
            int nextByte = stream.ReadByte();
           
            // End of stream? If so, we're done
            if (nextByte==-1)
            {
                return buffer;
            }
           
            // Nope. Resize the buffer, put in the byte we've just
            // read, and continue
            byte[] newBuffer = new byte[buffer.Length*2];
            Array.Copy(buffer, newBuffer, buffer.Length);       //-------- This code stalls right here.
            newBuffer[read]=(byte)nextByte;
            buffer = newBuffer;
            read++;
        }
    }
    // Buffer is now too big. Shrink it.
    byte[] ret = new byte[read];
    Array.Copy(buffer, ret, read);
    return ret;
}
0
 
j-trobecCommented:
No, there's actually a class called MemoryStream that allows you to create a stream and write bytes to it.  You don't have to specify an intial size or anything.  The big problem with the way you're trying to do it is that even when you get past the hang, you'll be creating TONS of new arrays which kills scalability.  Look up the MemoryStream class on msdn.  Like I was saying you can create one of these, wrap it in a BinaryWriter, read chunks from the incoming network stream and write them to the binary writer.  Then reset the MemoryStreams position to 0, get its length and use it in declaring a new array.  Fill the array by wrapping the MemoryStream in a BinaryReader and looping until you've read the entire stream....

Try that out, I'll post some code if you get into a jam.
0
What does it mean to be "Always On"?

Is your cloud always on? With an Always On cloud you won't have to worry about downtime for maintenance or software application code updates, ensuring that your bottom line isn't affected.

 
rawinnlnx9Author Commented:
This is extremely important to me so if I can I will be adding another 500 points to the solution for whoever helps me get around it.

That's 1000 points to the solution. (If I can do that. If you are a EE-Admin, let me know if I'm promising the impossible.)
0
 
rawinnlnx9Author Commented:
I'll take any code you have but I'm on my way to MSDN as soon as I hit submit.

Thanks in advance!
0
 
rawinnlnx9Author Commented:
I just realized I posted the wrong code. DUH! It does not even have MemoryStream in it...

Here's the routine I meant to show. This one dies to because
buffer.length is too big. I need to know the size ahead of time or
it fails.

public static byte[] ReadFully (Stream stream)
{
      byte[] buffer = new byte[32768];
      using (MemoryStream ms = new MemoryStream())
      {
            while (true)
            {
                  int read = stream.Read (buffer, 0, buffer.Length);
                  if (read <= 0)
                        return ms.ToArray();
                  ms.Write (buffer, 0, read);
            }
      }
}
0
 
rawinnlnx9Author Commented:
This is weird. The code above does not work but this code below works once.

Let me paste in all the code so you can see everything. I feel like I'm not giving the whole picture.

using System;
using System.Text;
using System.Net.Sockets;
using System.IO;

namespace SigStrength
{
      public class satTelnet
      {
            public satTelnet()
            {
            }
            public bool Connect(string Host, int Port,string cmdQuestionMark, string cmdC, string cmdG)

            {
                  TcpClient client = null;
                  byte[] read = null;
                  byte[] send = new byte [1];
                  int bytes = 0;
                  string data;

                  try
                  {
                        client = new TcpClient(Host,Port);
                  }
                  catch (Exception ex) //connection problem
                  {
                        throw ex;
                  }
                  
                  NetworkStream getStream = client.GetStream();
                  
                  read = ReadFully(getStream = client.GetStream());
                  data = Encoding.ASCII.GetString(read);
                  System.Diagnostics.Debug.WriteLine(data);
           
            send = Encoding.ASCII.GetBytes(cmdC);
                  getStream.Write(send,0,send.Length);
                  read = ReadFully(getStream = client.GetStream());
                  data = Encoding.ASCII.GetString(read);
                  System.Diagnostics.Debug.WriteLine(data); //- DEBUG PRINT
                  
                  send = Encoding.ASCII.GetBytes(cmdG);
                  getStream.Write(send,0,send.Length);
                  read = ReadFully(getStream = client.GetStream());
                  data = Encoding.ASCII.GetString(read);
                  System.Diagnostics.Debug.WriteLine(data); //- DEBUG PRINT
                  string retval = Encoding.ASCII.GetString(read);

                  getStream.Close();
                  client.Close();

                  if (retval[0]=='0')
                        return true;
                  else
                        return false;
            }

            public static byte[] ReadFully (Stream stream)
            {
                  byte[] buffer = new byte[32768];
                  using (MemoryStream ms = new MemoryStream())
                  {
                        int read = stream.Read (buffer, 0, buffer.Length);
                        ms.Write (buffer, 0, read);
                        return ms.ToArray();
                  }
            }
      }
}


0
 
j-trobecCommented:
well, here are a few things to consider:

in this method, you only read from the MemoryStream once, so the size is restricted to 32768 bytes and may not actually reach the end of the stream.

Try:

public static byte[] ReadFully (Stream stream)
{
      byte[] buffer = new byte[32768];
      int read = 0;

      using (MemoryStream ms = new MemoryStream())
      {
           do
         {
                read = stream.Read (buffer, 0, buffer.Length);
                ms.Write (buffer, 0, read);
           } while(read > 0);
           return ms.ToArray();
      }
}

another thing is that I don't find this notation particularly readable:

    read = ReadFully(getStream = client.GetStream());

which is personal preference, but I believe it is leading to some problems, for instance it looks like you are abandoning some of these streams, and they really should be disposed as soon as you are done using them.  Everytime you call getStream = client.GetStream(), the stream originally referred to by getStream would be left open...so, i'd recommend changing these lines:

read = ReadFully(getStream = client.GetStream());

to:

getStream.Dispose();
getStream = client.GetStream();
read = ReadFully(getStream);

so, maybe we can try those changes and see where that gets us?
0
 
rawinnlnx9Author Commented:
Okay, you were right MemoryStream was the ticket. The part of my code you needed to see most was missing. I was sending a "c" and a "g" using the Write method. Interestingly enough that doesn't work very well unless you make it "c\r\n" and "g\r\n". DUH!!! - DUH!!! - DUH!!! You've got to terminate the string. I'm such an idiot!!!

Okay, I've awarded you the points. If you want the other 500 I think I have to post a lame question let you answer and give you the 500 which is just fine with me. Let me know if you want them.

I'll make the changes you suggested using Dispose and I bet things get even better. :)

Let me know if you want the other 500. In my book they are yours.

- Rex
0
 
rawinnlnx9Author Commented:
getStream.Dispose() is restricted due to it's protection level.
0

Featured Post

Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

  • 7
  • 3
Tackle projects and never again get stuck behind a technical roadblock.
Join Now