Protobuf 校验和 (crc)
Posted
技术标签:
【中文标题】Protobuf 校验和 (crc)【英文标题】:Protobuf checksum (crc) 【发布时间】:2014-05-11 23:43:58 【问题描述】:我打算将一些大对象存储到数据库 (BLOB) 中。在我看来,protobuf 是序列化/反序列化 BLOB 的最佳候选者之一。尽管它具有二进制格式,但它仍然易于阅读和更改其内容(字符串、整数等)。所以我需要某种数据验证,无论何时原始 BLOB 或修改(被黑客?被太聪明的用户?)。
一种可能性是在表中有一个专用字段,称为crc
,计算 BLOB 的校验和并将其放在那里。但是当 crc 是 BLOB 本身的一部分时(在许多情况下)会好得多。
我可以在 protobuf 流的末尾添加 额外 个字节,但我必须删除它们(否则反序列化器会抛出异常“invalid field blablabla”)。
我可以将 protobuf 流放入包装器中,但解包/包装又是开销。
是否有一种简单且便宜的方法可以在 protobuf 流的末尾添加一些内容,以避免在反序列化期间需要额外的操作?在 XML 中,我可以添加注释。我认为 protobuf 中没有注释,但是如何将 1 或 2 个字节的 CRC 放在示例中?
【问题讨论】:
【参考方案1】:Crc 应该保存在之前。这使得通过使用Seek
(跳过标题)从流中反序列化变得微不足道。
这是最简单的实现:
// serialize
using (var file = File.Create("test.bin"))
using (var mem = new MemoryStream())
Serializer.Serialize(mem, obj); // serialize obj into memory first
// ... calculate crc
file.Write(new byte[] crc , 0, 1);
mem.WriteTo(file);
// deserialize
using (var file = File.OpenRead("test.bin"))
var crc = file.ReadByte();
// ... calculate and check crc
file.Seek(1, SeekOrigin.Begin);
Serializer.Deserialize<ObjType>(file);
【讨论】:
【参考方案2】:Protobuf 流是可附加的。如果您知道数据中不存在的字段编号,您可以简单地将数据附加到该字段。如果您打算添加 1 或 2 个字节的 CRC 数据,那么“varint”可能是您最好的选择(请注意,“varint”是 7 位编码格式,第 8 位是延续标记,因此您可能想要使用7、14 或 21 位或实际的 CRC 数据),那么您可以追加:
选择的字段编号,左移 3 位,然后 varint 编码 CRC 数据,varint 编码但是!问题在于解码器仍会经常解释和存储这些数据,这意味着如果您对其进行序列化,它会将这些数据包含在输出中。
避免这种情况的另一种方法是将 protobuf 数据封装到您自己设计的某种框架机制中。例如,您可以选择这样做:
4字节表示protobuf有效载荷长度,“n” “n”字节的 protobuf 负载 在“n”个字节上计算出的 2 个字节的 CRC 数据我可能会选择第二个选项。请注意,如果需要,您可以为长度前缀选择“varint”编码而不是固定长度编码。不过,对于 CRC 来说可能不值得,因为 将 是固定长度的。
【讨论】:
好的,那我就用header了。作为奖励,这将允许我进行版本控制,以防 protobuf 不能(例如,如果我决定突然创建一个基类,protobuf 将 not work with old i> 继承数据,只是对其进行了测试,例如,在XmlSerializer
中,继承某些东西不是问题)以上是关于Protobuf 校验和 (crc)的主要内容,如果未能解决你的问题,请参考以下文章