linux - protobuf如何判断一个值是属于可选字段,还是属于另一个对象?

标签 linux object protocol-buffers encode delimiter

例如,如果我这样定义一张照片:

$cat 30.proto
message hello
{
    required int32 f1=1;
    required int32 f2=2;
    optional int32 f3=3;
}

如果 protobuf 可以处理这样的事情,我会加倍:

  1. 我声明了 3 个对象,每个对象都没有 f3 字段。

  2. 写入输出

  3. 那么,在读者端,读者如何知道这6个值应该属于3个对象(每个2个字段),还是属于2个对象(每个3个字段)?

换句话说,编码字节中的“require”/“optional”是如何体现的?如果没有体现在字节流中,那么protobuf是如何确定一个新偏移量的开始呢?我们知道 protobuf 没有“分隔符”位。

我对此进行了简单的快速测试:

$cat 30.cpp
#include "30.pb.h"
#include<fstream>
using namespace std;
int main()
{
    fstream f("./log30.data",ios::binary|ios::out);
    hello p1,p2,p3,p4,p5;
    p1.set_f1(1);
    p1.set_f2(2);
    p2.set_f1(3);
    p2.set_f2(4);
    p3.set_f1(5);
    p3.set_f2(6);
    p1.SerializeToOstream(&f);
    p2.SerializeToOstream(&f);
    p3.SerializeToOstream(&f);

    p4.set_f1(7);
    p4.set_f2(8);
    p4.set_f3(9);
    p5.set_f1(0xa);
    p5.set_f2(0xb);
    p5.set_f3(0xc);
    p4.SerializeToOstream(&f);
    p5.SerializeToOstream(&f);
    return 0;
}

$g++ 30.cpp 30.pb.cc -lprotobuf && ./a.out && xxd log30.data
00000000: 0801 1002 0803 1004 0805 1006 0807 1008  ................
00000010: 1809 080a 100b 180c                      ........

我只是猜测字节流是否总是以最小的标记号开始,并随着它转储字节流而增加:当遇到较小的标记号时,它认为这是一个新对象的开始。只是我的粗略猜测。

需要你的解释!

最佳答案

(3) Then, in reader side, how does reader know that these 6 values should belong to 3 objects(each 2 fields), or belong to 2 objects(each 3 fields)?

In another word, how does the "require"/"optional" reflected inside encoded bytes? If not reflected in the byte stream, then how does protobuf determine the start of a new offset? We know protobuf don't have "delimiter" bits.

Protobuf 没有。在将消息提供给 protobuf 之前,由您(程序员)来拆分消息。

例如,运行这个程序:

#include "30.pb.h"
#include <fstream>
#include <iostream>
using namespace std;
int main()
{
    fstream f("./log30.data",ios::binary|ios::out);
    hello p1,p2,p3,p4,p5;
    p1.set_f1(1);
    p1.set_f2(2);
    p2.set_f1(3);
    p2.set_f2(4);
    p3.set_f1(5);
    p3.set_f2(6);
    p1.SerializeToOstream(&f);
    p2.SerializeToOstream(&f);
    p3.SerializeToOstream(&f);

    p4.set_f1(7);
    p4.set_f2(8);
    p4.set_f3(9);
    p5.set_f1(0xa);
    p5.set_f2(0xb);
    p5.set_f3(0xc);
    p4.SerializeToOstream(&f);
    p5.SerializeToOstream(&f);
    f.close();
    f.open("./log30.data", ios::binary|ios::in);

    hello hin;
    hin.ParseFromIstream(&f);

    cout << "f1: " << hin.f1() << ", f2: " << hin.f2() << ", f3: " << hin.f3() << "\n";
    return 0;
}

您应该只会看到上次序列化的 hello 对象的值,因为 protobuf 会读取整个 流并用新值覆盖旧值。

关于linux - protobuf如何判断一个值是属于可选字段,还是属于另一个对象?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41614027/

相关文章:

java - Ljava.lang.Object 错误 - Matlab/Java

linux - *nix 有平衡方案 REPL 吗?

linux - 无法在 VirtualBox Debian 8 中访问 Ajenti Web 面板端口

c# - 使用互斥锁来锁定对象

java - ArrayList x,y坐标距离计算

java - protobuf 中的小 int 值应该使用什么数据类型?

c# - Protobuf-net 有教程吗?

java - 处理来自 Google Protocol Buffer 库的 IOException

linux - PThread 库的源代码?

swift - '不安全指针<Int8 >' has no member ' toString'