ProtoBuf 在反序列化期间损坏字节数组(添加了额外的 0)
Posted
技术标签:
【中文标题】ProtoBuf 在反序列化期间损坏字节数组(添加了额外的 0)【英文标题】:ProtoBuf corrupts byte array during deserialization (extra 0's added) 【发布时间】:2013-07-21 03:30:43 【问题描述】:我正在使用 ProtoBuf.NET 来序列化/反序列化一些类。我发现在反序列化时,我得到了一个损坏的字节 [](额外的 0)。在你问之前,是的,我需要 ProtoBuf API 的 *WithLengthPrefix() 版本,因为 ProtoBuf 部分位于自定义流的开头:)
我明白了
Original object is (JSON depiction):
"ByteArray":"M+B6q+PXNuF8P5hl","ByteArray2":"DmErxVQ2y87IypSRcfxcWA==","K":2,"V
":1.0
Protobuf: Raw Hex (42 bytes):
29-2A-20-0A-0C-33-E0-7A-AB-E3-D7-36-E1-7C-3F-98-65-12-10-0E-61-2B-C5-54-36-CB-CE
-C8-CA-94-91-71-FC-5C-58-08-02-15-00-00-80-3F
Regenerated object is (JSON depiction):
"ByteArray":"AAAAAAAAAAAAAAAAM+B6q+PXNuF8P5hl","ByteArray2":"DmErxVQ2y87IypSRcf
xcWA==","K":2,"V":1.0
ByteArray
成员中额外的 AAA*A
基本上是 base64 中的十六进制 0x00。
应用逻辑类似
static void Main(string[] args)
var parent = new Parent();
parent.Init();
Console.WriteLine("\nOriginal object is (JSON depiction):");
Console.WriteLine(JsonConvert.SerializeObject(parent));
using (var ms = new MemoryStream())
Serializer.SerializeWithLengthPrefix(ms, parent, PrefixStyle.Base128);
byte[] bytes2 = ms.ToArray();
var hex2 = BitConverter.ToString(bytes2);
Console.WriteLine("\nProtobuf: Hex (0 bytes):\n1", bytes2.Length, hex2);
ms.Seek(0, SeekOrigin.Begin);
var backFirst = Serializer.DeserializeWithLengthPrefix<Parent>(ms,PrefixStyle.Base128);
Console.WriteLine("\nRegenerated object is (JSON depiction):");
Console.WriteLine(JsonConvert.SerializeObject(backFirst));
DTO 类是
[DataContract]
[ProtoContract]
internal class Parent : Child
[DataMember(Name = "ByteArray", Order = 10)]
[ProtoMember(1)]
public byte[] ByteArray get; set;
[DataMember(Name = "ByteArray2", Order = 30, EmitDefaultValue = false)]
[ProtoMember(2)]
public byte[] ByteArray2 get; set;
public Parent()
ByteArray = new byte[12];
internal void Init(bool bindRow = false)
base.Init();
var rng = new RNGCryptoServiceProvider();
rng.GetBytes(ByteArray);
ByteArray2 = new byte[16];
rng.GetBytes(ByteArray2);
[DataContract]
[ProtoContract]
[ProtoInclude(5, typeof(Parent))]
public class Child
[DataMember(Name = "K", Order = 100)]
[ProtoMember(1)]
public Int32 K get; set;
[DataMember(Name = "V", Order = 110)]
[ProtoMember(2)]
public float V get; set;
internal void Init()
K = 2;
V = 1.0f;
我确实看到,当我将 ByteArray = new byte[12]
从 Parent
构造函数移到它的 Init()
方法中时,ProtoBuf 工作正常。但是,我们有应用程序逻辑可以防止在真实版本中出现这种情况(与您在上面看到的 SO 修剪代码相比)。
是我们做错了什么还是 ProtoBuf 中的错误?
【问题讨论】:
【参考方案1】:我们开始吧:
public Parent()
ByteArray = new byte[12];
注意:protobuf 被设计为(由 google 设计)既可附加又可合并。其中追加/合并与“追加”是同义词(对于列表/数组等)。
两个选项(都可以通过属性):
禁用构造函数:[ProtoContract(SkipConstructor = true)]
禁用附加:[ProtoMember(1, OverwriteList = true)]
还有其他选择,但我倾向于这些。
您说数组初始化在实际代码中有所不同,但是:我无法评论我看不到的代码。
【讨论】:
init 非常相似,我的意思是其他类对此类的使用使得我无法过多地更改 ctor/init 例程(至少在没有重大重构的情况下不会)。谢谢回复,我会尽快查看。 @Sid 并且显示的内容均不涉及更改 ctor/init 例程【参考方案2】:我遇到了同样的问题,我的Bytestring
数据实际上是我从服务器获取的 XML 数据,所以在我的应用程序中我已经有一个 XML Serialaizer
,因此我决定使用它而不是引入为Photobuf
新建serializer
并装饰我所有的模型,我发现这项任务非常耗时。
这是我的函数,它将deserialize
我的Bytestring
。
public SceneDTO ParseSceneAsyncFromByteString(ByteString byteStringData)
var serializer = new CustomXmlSerializer(typeof(SceneDTO), _timingManager);
serializer.UnknownNode += OnUnknownNode;
serializer.UnknownAttribute += OnUnknownAttribute;
var ms = new MemoryStream(byteStringData.ToByteArray());
var scene = (SceneDTO) serializer.Deserialize(ms);
serializer.UnknownNode -= OnUnknownNode;
serializer.UnknownAttribute -= OnUnknownAttribute;
return scene;
我关注这个的另一个原因是我在使用 Photobuf
serializer
后收到以下错误。
源数据中出现意外的端组;这通常意味着来源 数据损坏 photobuf 解串器
即使在解决了这个问题之后,我的模型数据也总是为空,我决定不花很多时间来解决这个问题,因为我已经有了一个可行的解决方案。
【讨论】:
以上是关于ProtoBuf 在反序列化期间损坏字节数组(添加了额外的 0)的主要内容,如果未能解决你的问题,请参考以下文章