有没有办法标记每个 protobuf-net 记录的结尾

Posted

技术标签:

【中文标题】有没有办法标记每个 protobuf-net 记录的结尾【英文标题】:Is there a way to mark the end of each protobuf-net record 【发布时间】:2012-05-15 18:58:08 【问题描述】:

我将一系列 protobuf-net 对象保存在数据库单元中作为长度前缀 protobuf-net 对象的 Byte[]:

//retrieve existing protobufs from database and convert to Byte[]
object q = sql_agent_cmd.ExecuteScalar();
older-pbfs = (Byte[])q;

// serialize the new pbf to add into MemoryStream m
//now write p and the new pbf-net Byte[] into a memory stream and retrieve the sum

var s = new System.IO.MemoryStream();
s.Write(older-pbfs, 0, older-pbfs.Length);
s.Write(m.GetBuffer(), 0, m.ToArray().Length); // append new bytes at the end of old
Byte[] sum-pbfs = s.ToArray();

//sum-pbfs = old pbfs + new pbf. Insert sum-pbfs into database

这很好用。我担心的是如果有轻微的数据库损坏会发生什么。将不再可能知道哪个字节是长度前缀,并且必须丢弃整个单元格内容。是否还建议使用某种类型的 pbf 对象结束指示符(有点像文本文件中使用的 \n 或 EOF 指示符)。这样,即使一条记录损坏,其他记录也可以恢复。

如果是这样,在每个 pbf 末尾添加记录结束指示符的推荐方法是什么。

在 Visual Studio 2010 上使用 protobuf-netv2 和 C#。

谢谢 马尼什

【问题讨论】:

【参考方案1】:

如果您通过Serialize / Deserialize 使用普通消息,则不:这不是规范的一部分(因为格式被设计为可附加的)。

但是,如果您使用SerializeWithLengthPrefix,它将在消息开头转储长度;然后它将提前知道需要多少数据。你用DeserializeWithLengthPrefix反序列化,如果没有足够的数据它会大声抱怨。然而!如果您有 额外 数据,它不会抱怨,因为这个 too 被设计为可附加的。

就 Jon 的回复而言,*WithLengthPrefix 方法的默认用法就存储的数据而言与 Jon 建议的完全相同;它假装有一个包装对象并相应地表现。区别在于:

实际上不存在包装对象 “withlengthprefix”方法在单次出现后显式停止,而不是将任何以后的数据合并到同一个对象中(例如,用于将多个离散对象发送到单个文件或单个套接字)

这里两个“可附加”的区别在于,第一个表示“合并为一个对象”,而第二个表示“我期望多个记录”。

不相关的建议:

s.Write(m.GetBuffer(), 0, m.ToArray().Length);

应该是:

s.Write(m.GetBuffer(), 0, (int)m.Length);

(无需创建额外的缓冲区)

【讨论】:

非常感谢。一个相关的问题。 Serializer 是否具有可用于通过网络发送 Byte[] sum-pbfs 的方法。标准机制似乎是循环遍历 Byte[] 直到你到达终点。但是像 Serializer.send(clientStream, sum-pbfs) 这样的东西会很棒。 @Manish 我不明白这个问题;什么是“sum-pbfs”?如果使用 WithLengthPrefix 方法,它不会读取一条消息。您还可以创建一个固定长度的 ProtoReader IIRC,并使用它 - 或者可能有一个接受固定长度的反序列化重载(不记得,但在公共 API 上绝对很容易完成) 我很抱歉不够清晰。 sum-pbfs 在上面的代码 sn-p 中,它本质上是一个序列化 pbfs 的 Byte[]。通过套接字发送 byte[] 的所有示例都表明我们一次循环通过它 2kb。我希望可能有一种更简单的方式来传输字节 []。但是在你的cmetshere之后,我想我还是会一次发送一个pbf。谢谢。【参考方案2】:

(注意:我对protobuf-net本身了解不多,但这一般适用于Protocol Buffer消息。)

通常,如果您想记录多条消息,只需放置一个“包装器”消息 - 使“真实”消息成为其中的重复字段。然后,每个“真实”消息的长度都会以 Protocol Buffers 的自然线格式为前缀。

这当然不会检测到损坏 - 但老实说,如果数据库最终损坏,您就会遇到更大的问题。您可能检测损坏,例如通过将散列与每条记录一起保存......但您需要考虑在长度前缀内或散列本身内发生损坏的可能性。想一想您在此处真正想要达到的目标 - 您想要防范的场景以及您需要的恢复水平。

【讨论】:

非常感谢您的反馈。我终于找到了一种方法来查看 protobuf-net 是否允许重复字段。事实并非如此。我可以看到一个字段的 IsRepeated = True 选项,但不是 IsRepeated = True。 @Manish:它肯定会处理重复的字段。我希望它们被建模为集合。

以上是关于有没有办法标记每个 protobuf-net 记录的结尾的主要内容,如果未能解决你的问题,请参考以下文章

在 protobuf-net 中,有没有办法指定在序列化/反序列化给定类型时要使用的自定义方法?

有没有办法将 IReadOnlyCollection<T>/IReadOnlyList<T> 与 protobuf-net 一起使用

交错 protobuf-net 和文件

Protobuf-Net 无法在没有无参数构造函数的情况下反序列化记录

将多个输入文件分类为单个输出文件,并带有尾标标记每个输入文件的结束位置?

Protobuf-net 是不是有计划包括验证?