Protobuf校验和(crc)

时间:2014-04-01 09:32:27

标签: protocol-buffers crc

我要将一些大对象存储到数据库(BLOB)中。正如我所见,protobuf是序列化/反序列化BLOB的最佳候选者之一。尽管它具有二进制格式,但仍然易于阅读和更改其内容(字符串,整数等)。所以我需要某种数据验证,无论何时它的原始 BLOB或修改过(黑客?太聪明的用户?)。

一种可能性是在表中有一个专用字段,称之为crc,计算BLOB的校验和并将其放在那里。但是,当crc是BLOB本身的一部分时,它会好得多(在许多情况下)。

我可以在protobuf流的末尾添加额外的字节,但我必须删除它们(或者反序列化器会抛出异常"无效字段blablabla&# 34。)

我可以将protobuf流放入包装器中,但是打开/包装也是开销。

是否有一种简单且便宜的方法可以在protobuf流的末尾添加一些内容,以避免在反序列化过程中需要额外的操作?在XML中,我可以添加注释。我不认为protobuf中有注释,但是如何将CRC作为1或2个字节的例子?

2 个答案:

答案 0 :(得分:5)

Protobuf流是可附加的。如果您知道数据中不存在的字段编号,则只需在该字段附加数据即可。如果您打算添加1或2个字节的CRC数据,那么“varint”可能是您最好的选择(注意“varint”是7位编码格式,第8位是延续标记,所以您可能想要使用7,14或21位或实际的CRC数据),然后你可以追加:

  • 选择的字段编号,左移3位,然后是varint编码
  • CRC数据,varint编码

然而!这里的皱纹是解码器仍然经常解释和存储这些数据,这意味着如果你序列化它,它将把这些数据包含在输出中。

另一种避免这种情况的方法是在你自己设计的某些框架机制中封装 protobuf数据。例如,您可以选择:

  • 4个字节表示protobuf有效负载长度,“n”
  • protobuf有效负载的“n”字节
  • 通过“n”字节计算的2个字节的CRC数据

我可能会选择第二种选择。请注意,如果需要,可以为长度前缀选择“varint”编码而不是固定长度编码。但是,对于CRC来说可能不值得,因为固定长度。

答案 1 :(得分:2)

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);
}