c# Stream Reading and Deserialization
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?
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.
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;
...
精彩评论