1

我曾使用 BinaryFormatter 通过 NetworkStream 序列化对象 像这样的代码

//OpenConnection ...
TCPClient client = server.AcceptTCPConnection();
Message message = new Message("bla bla"); // This is the serializable class
NetworkStream stream = client.GetStream(); // Get Stream
BinaryFormatter bf = new BinaryFormatter();
bf.Serialize(stream, message);
stream.Flush();
stream.Close(); //Close Connection

而在客户端代码中,我们只需要从流中读取 bf.Deserialize(stream) as Message 来获取我们刚刚从服务器发送的对象。

但是这里有一个问题,如果我删除stream.Close();了客户端无法读取这个对象的行。或者我可以更改为stream.Dispose();

但是,我想再次使用此流发送另一个Message,我该怎么办?请帮忙,这让我感到很头疼@@

更新: 我找到了这个问题的原因。因为我用一台机器同时运行客户端和服务器。它肯定在两台不同的机器上运行良好。有人可以告诉我为什么吗?几天前遇到大问题。

4

1 回答 1

3

发送多个单独的消息涉及“框架” - 将单个通道分成单独的块,这些块不需要客户端“读取结束”。不过,奇怪的是,我的印象是BinaryFormatter 已经实现了基本框架——但是:我可能是错的。在一般情况下,当使用二进制协议时,最常见的方法是在每条消息前面加上有效载荷的长度,即

using(var ms = new MemoryStream()) {
    while(...)
    {
        // not shown: serialize to ms

        var len BitConverter.GetBytes((int)ms.Length);
        output.Write(len, 0, 4);
        output.Write(ms.GetBuffer(), 0, (int) ms.Length);
        ms.SetLength(0); // ready for next cycle
    }
}

来电者必须:

  • 准确读取 4 个字节(至少,对于上述内容),或检测 EOF
  • 确定长度
  • 准确读取那么多字节
  • 反序列化
  • 重复

如果这听起来像是很多工作,也许只需使用一个为您完成所有这些工作的序列化程序;例如,使用 protobuf-net,这将是:

while(...) { // each item
    Serializer.SerializeWithLengthPrefix(output, PrefixStyle.Base128, 1);
}

读者将是:

foreach(var msg in Serializer.DeserializeItems<Message>(
       input, PrefixStyle.Base128, 1))
{
   // ...
}

(注意:这不使用与 相同的格式/规则BinaryFormatter

于 2013-10-25T11:22:50.920 回答