我有这样的代码:
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;
}
不幸的是,流对象总是一个TCP流,这意味着没有查找操作。那么,我如何检查以确保我没有超出我放置//HERE注释的流呢?
我认为没有任何方法可以查询NetworkStream
以找到您正在寻找的数据。你可能需要做的是将流提供的任何数据缓冲到另一个数据结构中,然后一旦你知道它有足够的字节,就从该结构中解析对象。
NetworkStream
类提供了一个DataAvailable
属性,它告诉您是否有任何数据可以读取,Read()
方法返回一个值,表明它实际检索了多少字节。您应该能够使用这些值来执行所需的缓冲。
见Skeets先生页面
有时候,你事先不知道流的长度(例如网络流),只是想把整个流读入缓冲区。这里有一个方法可以做到这一点:
/// <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);
}
}
}
这应该给你一些想法。一旦有了字节数组,检查Length
就很容易了。
在您的示例中,它看起来像这样:
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;
...