C#流读取和反序列化

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;
}

不幸的是,流对象始终将是TCP流,这意味着没有寻找操作。那么,我如何检查以确保我没有超过放置// HERE注释的流?


你是否能够控制通过网络发送的内容?如果是,那么在序列化对象时,你可以在另一端写下你要发送的字节数。 - gyurisc
是的,我有(请看“int length = br.ReadInt32()”这一行)。但现在我又遇到了一个新的错误。我应该为此提一个新问题吗? - Xenoprimate
@Motig - 是的,如果是一个新问题,你应该创建一个新的问题。 - SwDevMan81
2个回答

3
我认为没有任何方法可以查询NetworkStream以找到您要查找的数据。您可能需要将流可用的任何数据缓冲到另一个数据结构中,然后在知道该结构具有足够字节时从该结构中解析对象。 NetworkStream类提供了一个DataAvailable属性,告诉您是否有任何可读取的数据,而Read()方法返回一个值,指示它实际检索了多少字节。您应该能够使用这些值来执行所需的缓冲操作。

2

请查看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;
...

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接