Protocol buffers 协议校验和(crc)

Protocol buffers 协议校验和(crc),protocol-buffers,crc,Protocol Buffers,Crc,我将把一些大对象存储到数据库(BLOB)中。在我看来,protobuf是序列化/反序列化BLOB的最佳候选者之一。尽管它有二进制格式,但仍然很容易读取和更改其内容(字符串、整数等)。因此,我需要某种数据验证,无论何时它的原始BLOB或修改(由黑客?由太聪明的用户?) 一种可能是在表中有一个专用字段,称之为crc,计算BLOB的校验和并将其放在那里。但如果crc是BLOB本身的一部分,情况会好得多(在许多情况下) 我可以在protobuf流的末尾添加额外的字节,但我必须删除它们(否则反序列化程序将

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

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

我可以在protobuf流的末尾添加额外的字节,但我必须删除它们(否则反序列化程序将抛出异常“invalid field bla”)

我可以将protobuf流放入包装器中,但展开/包装同样需要开销


有没有一种简单而廉价的方法可以在protobuf流的末尾添加一些东西,以避免在反序列化过程中需要额外的操作?在XML中,我可以添加注释。我认为protobuf中没有注释,但如何将1或2字节的CRC放入示例中?

protobuf流是可追加的。如果您知道数据中不存在的字段号,只需针对该字段添加数据即可。如果您打算添加1或2字节的CRC数据,那么“varint”可能是您最好的选择(注意,“varint”是一种7位编码格式,第8位为连续标记,因此您可能希望使用7、14或21位或实际的CRC数据),然后您可以添加:

  • 选择的字段编号,左移3位,然后进行变量编码
  • CRC数据,可变编码
然而!这里的缺点是解码器仍然经常解释和存储这些数据,这意味着如果您对其进行序列化,它将在输出中包含这些数据

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

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

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

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);
}
//序列化
使用(var file=file.Create(“test.bin”))
使用(var mem=new MemoryStream())
{
Serializer.Serialize(mem,obj);//首先将obj序列化到内存中
//…计算crc
写入(新字节[]{crc},0,1);
mem.WriteTo(文件);
}
//反序列化
使用(var file=file.OpenRead(“test.bin”))
{
var crc=file.ReadByte();
//…计算并检查crc
Seek(1,SeekOrigin.Begin);
反序列化(文件);
}

好的,我将使用页眉。作为奖励,这将允许我在protobuf无法实现的情况下进行版本控制(例如,如果我决定突然创建基类,protobuf将无法处理旧的继承数据,只需对其进行测试,而在
XmlSerializer
中,生成继承的数据并不是问题)