gpt4 book ai didi

c# - 如何知道要使用 protobuf-net 反序列化的字节数组的长度?

转载 作者:行者123 更新时间:2023-12-03 20:38:09 27 4
gpt4 key购买 nike

我正在尝试使用内存映射文件将 C# 对象从一个进程发送到另一个进程,并且我正在尝试使用 BinaryFormatter 或 protobuf-net。两者都不起作用 - 显然是因为我必须使用固定长度的字节数组,而 protobuf-net 需要一个完全正确长度的数组?

使用 protobuf-net,我在反序列化时遇到此异常:“ProtoException:'缓冲区中留下未使用的数据;这表明输入已损坏'在这一行:“message1 = Serializer.Deserialize(memoryStream);

这是我的代码。此时,我只是尝试一个简单的示例,以便让它在基本级别上工作:这是我想要在程序之间发送的对象:

[ProtoContract]
public class IpcMessage
{
public IpcMessage() { }

[ProtoMember(1)]
public string title { get; set; }

[ProtoMember( 2 )]
public string content { get; set; }
}

这是发送 IpcMessage 对象的(简化的 - 我删除了同步)代码:

static void SampleSend()
{
// Create the memory-mapped file which allows 'Reading' and 'Writing'
using (MemoryMappedFile mmf = MemoryMappedFile.CreateOrOpen( "MyMmfName", 1024, MemoryMappedFileAccess.ReadWrite ))
{
// Create a view-stream for this process, which allows us to write data from offset 0 to 1024 (whole memory)
using (MemoryMappedViewStream mmvStream = mmf.CreateViewStream( 0, 1024))
{
IpcMessage message1 = new IpcMessage();
message1.title = "test";
message1.content = "hello world";
Serializer.Serialize( mmvStream, message1 );
}
}
}

这是接收程序中的代码(稍微简化):

// Create the memory mapped file..
using (MemoryMappedFile mmf = MemoryMappedFile.CreateOrOpen( "MyMmfName", 1024, MemoryMappedFileAccess.ReadWrite ))
{
using (MemoryMappedViewAccessor mmvStream = mmf.CreateViewAccessor( 0, 1024, MemoryMappedFileAccess.Read ))
{
byte[] buffer = new byte[1024];
IpcMessage message1;
int numberBytesRead = mmvStream.ReadArray<byte>( 0, buffer, 0, 1024 );
var memoryStream = new MemoryStream(buffer);
// It is at this next line that I get ProtoException: 'Unconsumed data left in the buffer; this suggests corrupt input'
message1 = Serializer.Deserialize<IpcMessage>( memoryStream );
}
}

当我尝试使用 BinaryFormatter 时,它也提示了。显然我做的事情基本上是错误的。

查看其他问题 - 我发现大多数实现似乎都有一个分配了正确长度的字节数组。在这里,我事先并不知道长度——它只是一个固定长度的 1024 字节数组(我随意选择了这个大小,只是暂时的)。或者也许我错过了一些明显的东西?

这是我第一次使用内存映射文件或 protobuf-net。如有任何帮助或建议,我们将不胜感激 - 预先感谢您。

注意:我使用的是 Visual Studio 2017 Enterprise 15.9.6,此代码面向 .NET Framework 4.0

最佳答案

选项 1:告诉 MemoryStream 在可选构造函数重载中使用的正确字节数;这适用于所有序列化器。

选项 2,专门针对 protobuf-net:使用 ProtoReaderDeserialize API 接受 Stream ProtoReader;后者可以用名义长度构造并且不会过度读取

选项 3,还是 protobuf-net:使用 *WithLengthPrefix API 进行序列化和反序列化

请注意,任何选项都假设您的代码可以可靠地确定长度,通常应以您使用的任何“框架”方法单独传达长度。选项 3 在内部处理这个问题,但在许多情况下,您自己的代码仍然需要具有帧感知能力,这样您就不会消耗太多信息并读取下一条消息(除非这是每个数据包只有一帧的 UDP,但是...它不是,因为 MemoryMappedFile)。您还需要考虑如果有效负载大于预期缓冲区大小会发生什么。

最简单的“成帧”方法是在每个逻辑 block 的开头保留 4 个字节;从偏移量 4 开始序列化,然后在偏移量 0-thru-3 处写入写回的字节数,使用您选择的字节序(通常为“小”)中的固定 4 字节布局。读取时:读取前 4 个字节以获取长度,然后消耗该段中的多个字节。这本质上是 *WithLengthPrefix 内部所做的事情,除了支持一些不同的布局选项。

关于c# - 如何知道要使用 protobuf-net 反序列化的字节数组的长度?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54465900/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com