3

I have this code:

public static List<ReplicableObject> ParseStreamForObjects(Stream stream) { List<ReplicableObject> result = new List<ReplicableObject>(); while (true) { // HERE I want to check that there's at least four bytes left in the stream BinaryReader br = new BinaryReader(stream); int length = br.ReadInt32(); // HERE I want to check that there's enough bytes left in the stream byte[] bytes = br.ReadBytes(length); MemoryStream ms = new MemoryStream(bytes); ms.Position = 0; result.Add((ReplicableObject) Formatter.Deserialize(ms)); ms.Close(); br.Close(); } return result; } 

Unfortunately, the stream object is always going to be a TCP stream, which means no seek operations. So how can I check to make sure that I'm not over-running the stream where I've put the // HERE comments?

3
  • Do you happen to have control over what is sent over the wire? if yes, then you can simply write on the other side how many bytes you are sending over when serializing your objects... Commented Sep 1, 2011 at 17:18
  • Yes, I do, and I have (see the line 'int length = br.ReadInt32()'). But now I get a new error. Should I make a new question for it? Commented Sep 1, 2011 at 17:26
  • @Motig - Yes, you should create a new question if it is a new issue Commented Sep 1, 2011 at 17:29

2 Answers 2

3

I don't think there's any way to query a NetworkStream to find the data you're looking for. What you'll probably need to do is buffer whatever data the stream makes available into another data structure, then parse objects out of that structure once you know it's got enough bytes in it.

The NetworkStream class provides a DataAvailable property that tells you if any data is available to be read, and the Read() method returns a value indicating how many bytes it actually retrieved. You should be able to use those values to do the buffering you need.

Sign up to request clarification or add additional context in comments.

Comments

2

See Mr. Skeets page

Sometimes, you don't know the length of the stream in advance (for instance a network stream) and just want to read the whole lot into a buffer. Here's a method to do just that:

/// <summary> /// Reads data from a stream until the end is reached. The /// data is returned as a byte array. An IOException is /// thrown if any of the underlying IO calls fail. /// </summary> /// <param name="stream">The stream to read data from</param> 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); } } } 

This should give you some ideas. Once you have the byte array, checking the Length will be easy to do.

In your example, it would look something like this:

int bytes_to_read = 4; byte[] length_bytes = new byte[bytes_to_read]; int bytes_read = stream.Read(length_bytes, 0, length_bytes.Length); // Check that there's at least four bytes left in the stream if(bytes_read != bytes_to_read) break; int bytes_in_msg = BitConverter.ToInt32(length_bytes); byte[] msg_bytes = new byte[bytes_in_msg]; bytes_read = stream.Read(msg_bytes, 0, msg_bytes.Length); // Check that there's enough bytes left in the stream if(bytes_read != bytes_in_msg ) break; ... 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.