protobuf.net反序列化器无限期等待

3
我有一个简单的TCP监听器,用于监听连接。一旦建立了连接,该方法会尝试发送数据,服务器端会尝试读取。
客户端代码:
using (NetworkStream stream = new NetworkStream(_client.Client, false))
            {
                Serializer.Serialize(stream, MyPersonObject);
            }

服务器端:

using (NetworkStream stream = new NetworkStream(_client.Client, false))
            {
                var myObject = Serializer.DeSerialize<Person>(stream);
            }

然而,我注意到一旦它到达 DeSerialize 方法,它就会挂起并无限期地等待。 请注意使用完全相同的步骤时,使用 BinaryFormatter 不会发生这种情况。 我不确定出了什么问题。

1个回答

4

protobuf流不会被“关闭” - 默认情况下,它会读取直到流结束,这意味着它会一直读取,直到入站TCP套接字被标记为完成。

如果您打算发送多个消息,请尝试使用序列化和反序列化的“WithLengthPrefix”版本; 这为您添加了消息框架,使其知道每个有效载荷的末尾在哪里。


1
在这个上下文中,我指的是传入的接收套接字(源发送套接字)需要已关闭。否则,流是打开的。要在套接字上发送多个消息,您需要框架;这就是“WithLengthPrefix”提供的内容。相比之下,BinaryFormatter内置了框架,这很好:但protobuf格式由Google定义,而不是我 - 所以我不能单方面添加它 :)如果您只发送一条消息:在写完后只需关闭发送管道即可。 - Marc Gravell
好的,因此在每个发送的消息中都有消息框架,这告诉接收者每个消息的确切大小,因此即使流没有定义长度,它也知道应该接收数据的确切大小。我想知道为什么NetworkStream没有长度。 - Enlight
@NPras 很抱歉回复晚了,但我一直在检查这个问题,突然想到一个问题。如果MemoryStream有一个定义好的长度(内存量),而Protobuf的序列化器没有消息框架,这意味着接收者(MemoryStream)不知道它有多大,那么为什么它能正常工作呢? - Enlight
@Enlight 正是;除非另一端关闭其出站套接字,否则您无法检测到NetworkStream的结束,这意味着不会再 有任何 数据到达;或者换句话说,如果您发送了正好一个帧并关闭了出站,那么您可以使用NetworkStream来完成此操作-然后接收器只需在其入站上读取直到EOF。 - Marc Gravell
MemoryStream在这里扭曲了你的思维; 流是“管道”,而不是“桶”-它们通常不包含任何东西-它们更多是一个API来获取某些东西。 MemoryStream实际上有字节这一事实是MemoryStream泄漏的实现细节。然而,你应该关注“数据是否可以被获取?” - 在NetworkStream上,如果没有任何本地缓冲区,则答案是“我不知道是或否,直到我看到更多字节或套接字关闭”; MemoryStream可以立即更明确地回答,因此它不会造成阻塞。 - Marc Gravell
显示剩余16条评论

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