Protobuf 如何编码 oneof 消息结构 [英] How Protobuf encodes oneof message construct

查看:620
本文介绍了Protobuf 如何编码 oneof 消息结构的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

对于这个在编码时运行 protobuf 编码的 python 程序给出以下输出:

For this python program running protobuf encoding when encoded gives following output:

0a 10 08 7f 8a 01 04 08 02 10 03 92 01 04 08 02 10 03 18 01

0a 10 08 7f 8a 01 04 08 02 10 03 92 01 04 08 02 10 03 18 01

我不明白的是,为什么 8a 之后是 01,为什么 92 之后是 01.似乎对于 oneof 类型的信息元素,添加了额外的 01,但为什么呢?请帮助我,如果有人理解 protobuf 编码

What I don't understand is why there is a 01 after 8a, and again why 01 after 92. Seems for information element of type oneof, extra 01 is added, but why? Please help me, if any body understands protobuf encoding

import sys
import test2_pb2

def write_to_file(file,value):
    with open(file, "wb") as f:
        f.write(value)

def cell_test_dct():

  msg=test2_pb2.TestPrimM();
  msg.textx=1
  msg.testmsg.testint=127
  msg.testmsg.prbbundlingtype.x =2
  msg.testmsg.prbbundlingtype.static=
   test2_pb2.BUNDLE_SIZE_N_4_WIDEBAND
  msg.testmsg.bundlingtype.x =2
  msg.testmsg.bundlingtype.static=
  test2_pb2.BUNDLE_SIZE_N_4_WIDEBAND
  print (msg)
  str = msg.SerializeToString()
  #write_to_file("/tmp/protobuf_test_file.bin",str)

def main_test():
    cell_test_dct()

main_test()

对于以下 protobuf 文件:

For the following protobuf file :

package NR_TEST;

enum BundleSizeE {
    BUNDLE_SIZE_N_4 = 0;
    BUNDLE_SIZE_WIDEBAND = 1;
    BUNDLE_SIZE_N_2_WIDEBAND = 2;
    BUNDLE_SIZE_N_4_WIDEBAND = 3;
}

message DynamicBundleSizesM {
    // bundleSizeSet1
    optional BundleSizeE bundleSizeSet1 = 1;
    // bundleSizeSet2
    optional BundleSizeE bundleSizeSet2 = 2;
}

message PrbBundlingTypeM {
    optional uint32 x=1;
    oneof BundlingTypeC {
    BundleSizeE static = 2;
    DynamicBundleSizesM dynamic = 3;
    }
}

message Test {
    required int32 testint   =1;
    required PrbBundlingTypeM prbbundlingtype = 17;
    required PrbBundlingTypeM bundlingtype = 18;
}
message TestPrimM
{
  oneof TestMsgC {
    Test testmsg=1;
    int32  nomsg=2;
    }
    required  int32 textx=3;
}

推荐答案

Given protobuf 编码您的留言如下:

Given protobuf encoding your message is as follows:

0a .. varint key '1|010' -> field 1, type LENGTH_DELIMITED
    10 .. varint length -> 16
    Contents:
        08 .. varint key '1|000' -> field 1, type VARINT
            7f .. varint value -> 127
        8a 01 .. varint key '00000010001|010' -> field 17, type LENGTH_DELIMITED
            04 .. varint length -> 4
            Contents:
                08 .. varint key '1|000' -> field 1, type VARINT
                    02 .. varint value -> 2
                10 .. varint key '10|000' -> field 2, type VARINT
                    03 .. varint value -> 3
        92 01 .. varint key '00000010010|010' -> field 18, type LENGTH_DELIMITED
            04 .. varint length -> 4
            Contents:
                08 .. varint key '1|000' -> field 1, type VARINT
                    02 .. varint value -> 2
                10 .. varint key '10|000' -> field 2, type VARINT
                    03 .. varint value -> 3
18 .. varint key '11|000' field 3, type VARINT
    01 .. varint value -> 1

长度分隔字段 17 的标记的整数值为二进制:10001|010(10001 为 17,010 为长度-分隔的 wire type) -> 给出 10001010(二进制).

Integer value for tag of length-delimited field 17 is in binary: 10001|010 (10001 is 17 and 010 is length-delimited wire type) -> giving 10001010 (binary).

要将此数字编码为 varint,您需要将总位长调整为 7 的倍数(用零填充):

To encode this number as varint you need to adjust total bit length to a multiple of 7 (fill with zeroes):

-> 00000010001010

-> 00000010001010

然后将其分成 7 位一组:

Then split it into groups of 7 bits:

-> 0000001 0001010

-> 0000001 0001010

然后颠倒这些组的顺序:

Then reverse the order of those groups:

-> 0001010 0000001

-> 0001010 0000001

并为每个组添加一个额外的位 (MSB) -- 零到最后一组和所有其他组一个(MSB 等于 1 告诉解析器后面还有另一组):

And add an extra bit to each group (MSB) -- zero to the last group and one to all other groups (MSB equal to 1 tells parser that there is another group following):

-> 10001010 00000001

-> 10001010 00000001

其中以十六进制形式给出 0x8A 0x01(您的值).

Which gives 0x8A 0x01 in hexadecimal (your value).

Varint 编码在此处描述.

Varint encoding is decribed here.

据我所知,oneof 结构不会改变连线格式(它只扩展了解析器逻辑,它忽略了所有,但忽略了单个 oneof 组中的最后一个字段).

As far as I know the oneof construct does not change the wire format (it only extends parser logic that it ignores all, but the last field from a single oneof group).

祝你好运!

这篇关于Protobuf 如何编码 oneof 消息结构的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆