二进制格式化程序异常

8
我正在尝试将一个对象图从服务器进程移动到客户端,当客户端和服务器都在我的开发虚拟机上时,它可以工作。当我在基础机器上运行服务器(客户端在dev vm上)时,它也可以工作。但是,当我在媒体中心PC上运行服务器时,它停止工作。异常信息如下: 二进制流“0”不包含有效的BinaryHeader。可能的原因是序列化和反序列化之间的无效流或对象版本更改。 所有三台PC都是x64 Windows 7机器。我使用TCPClient和TCPListener以及BinaryFormatter类来进行重型操作。 传输的数据是使用标准的FileStream对象从文件中读取的。 如果在客户端端将缓冲区序列化到文件中,根据BeyondCompare,内容似乎确实有所不同?! 我的对象上的所有字符串属性都在setter中进行了Base64编码,并在getter中进行了解码。 我可以发布代码,但我不确定问题出在哪里?有什么想法吗?

确保所有已加载的程序集实际上是相同版本且为同一程序集。此外,我不理解在二进制序列化场景中使用Base64编码的意义。 - leppie
@leppie,是的 - 所有程序集绝对相同。Base64 的东西只是最后一丝努力尝试隔离任何编码奇怪性 - 我绝对不是使用 BinaryFormatter 的专家。 - 6footunder
1个回答

阿里云服务器只需要99元/年,新老用户同享,点击查看详情
1
更新:我似乎解决了这个问题。我在客户端读取服务器响应的地方设置了断点。
tcpClient.GetStream().Read(buffer, 0, buffer.Length);

并且注意到从“问题”服务器读取的字节数较少。经过快速搜索,我找到了这篇文章http://social.msdn.microsoft.com/Forums/en-US/ncl/thread/759f3f2f-347b-4bd8-aa05-fb7f681c3426,其中Dave Murray建议:

有几种更优雅的处理方式。如果您不打算将连接用于其他任何事情,则最简单的方法是nobugz所建议的。当服务器完成发送数据时,请关闭连接的末尾。当客户端在关闭之前读取所有已发送的数据时,Read将开始返回0,此时您就知道服务器不打算再发送任何内容。

因此,我将我的代码从单个读取更新为:

var buffer = new byte[32768];
var totalBytesRead = 0;
var bytesRead = tcpClient.GetStream().Read(buffer, 0, buffer.Length);

do
{
      totalBytesRead += bytesRead;
      bytesRead = tcpClient.GetStream().Read(buffer, totalBytesRead, bytesRead);

} while (bytesRead > 0);

我已经根据帖子中的内容更新了我的服务器代码,以关闭连接。根据@leppie的评论,我可能可以删除我的Base64包装属性...


是的,不检查Read的结果是一个错误。然而,固定缓冲区也是一个错误,除非您事先知道长度。更好的方法是将其推入MemoryStream中。或者:直接从TCP流反序列化。 - Marc Gravell
@Marc - 谢谢,同意 - 这是 POC 代码,但这并不能为糟糕的编码开脱。我现在将删除固定大小缓冲区,并直接读入内存流。关于“直接从 TCP 流反序列化”,我的问题是,如果 tcpClient 分块读取,那么该怎么办?在反序列化之前必须读取整个消息吗? - 6footunder
因为TCP客户端作为“流”存在,所以您不需要整个消息;调用者可以根据自己的喜好选择数据。 - Marc Gravell

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