Protocol buffers 如何解释协议缓冲区的嵌入式消息二进制线格式?

Protocol buffers 如何解释协议缓冲区的嵌入式消息二进制线格式?,protocol-buffers,Protocol Buffers,我试图理解协议缓冲区编码方法,当将消息转换为二进制(或十六进制)格式时,我无法理解嵌入的消息是如何编码的 我想可能和内存地址有关,但我找不到确切的关系 这就是我所做的 步骤1:我在test.proto文件中定义了两条消息 syntax = "proto3"; package proto_test; message Education { string college = 1; } message Person { int32 age = 1; string name

我试图理解协议缓冲区编码方法,当将消息转换为二进制(或十六进制)格式时,我无法理解嵌入的消息是如何编码的

我想可能和内存地址有关,但我找不到确切的关系

这就是我所做的

步骤1:我在
test.proto
文件中定义了两条消息

syntax = "proto3";
package proto_test;

message Education {
    string college = 1;
}

message Person {
    int32 age = 1;
    string name = 2;
    Education edu = 3;
}
步骤2:然后我生成了一些
go
code

protoc --go_out=. test.proto
步骤3:然后我检查消息的编码格式

p:=proto_test.Person{
年龄:666,
姓名:“汤姆”,
教育部:&proto_测试教育部{
大学:“某处”,
},
}
变量b[]字节
out,err:=p.XXX\u封送员(b,true)
如果出错!=零{
log.Fatalln(“封送失败,错误:”,err)
}
fmt.Printf(“十六进制格式:%x\n”,输出)
fmt.Printf(“二进制格式:%b\n”,输出)
哪些输出

十六进制格式:08 9a 05 12 03 54 6f 6d 1a fd 96 d1 08 0a 09 53 4f 4d 45 57 48 45
二进制格式:[1000 10011010 101 10010 11 1010100 1101111 1101101 11010 111111 01 10010110 11010001 1000 1010 1001 1010011 1001111 1001101 1000101 1010111 1001000 1010010 1000101]
我的理解是

08-标签号为1的int32导线类型
9a 05-666的品种
12-标签号为2的串线类型
03-长度分隔符,即3字节
54 6f 6d-ascii表示“TOM”
1a-带标签号3的嵌入式消息线类型
fd 96 d1 08-?(以下是我不明白的)
0a-位号为1的串导线类型
09-以9字节分隔的长度
53 4f 4d 45 57 48 52 45-ascii表示“某处”
fd 96 d1 08
代表什么? 似乎d108总是在那里,但是fd96有时会改变,不知道为什么。谢谢回答:)


添加


我调试了封送处理并报告了一个错误。

在该位置,我/您可能会期望嵌入消息中的字节数

0x08
0x9A, 0x05
0x12
0x03
0x54 0x6F 0x6D
0x1A 
0x0B                        <- Equals to 11 decimal.
0x0A
0x09
0x53 0x4F 0x4D 0x45 0x57 0x48 0x45 0x52 0x45
我已经用Python重复了你的实验

msg = Person()
msg.age = 666
msg.name = "Tom"
msg.edu.college = "SOMEWHERE"
我得到了一个不同的结果,一个我期待的结果。说明嵌入消息大小的变量

0x08
0x9A, 0x05
0x12
0x03
0x54 0x6F 0x6D
0x1A 
0x0B                        <- Equals to 11 decimal.
0x0A
0x09
0x53 0x4F 0x4D 0x45 0x57 0x48 0x45 0x52 0x45
这样做的结果是完美的:

age: 666
name: "Tom"
edu {
  college: "SOMEWHERE"
}

我得出的结论是Protobuf中有一些不同的编码方式。我不知道在这种情况下该怎么办,但我知道负32位变量的例子。一个正变量用五个字节编码,一个负变量用64位值转换并编码为十个字节。

@QiankunZhang我忘了提到你可以尝试反序列化这个python代码生成的字节数组,看看你是否得到了一个有效的消息。我想会的。“我得出的结论是Protobuf中有一些不同的编码方式”-嗯,这有点正确,但在这种情况下,我认为问题是显示的十六进制是损坏的,可能与printf有关;问题中显示的十六进制根本无效protobuf@MarcGravell这是否意味着当我反序列化乾坤的字节数组时,代码将跳过无效部分?我确实从中得到了一个有效的信息。是否有一种机制可以在嵌套消息的长度无效的情况下扣除该长度?我很困惑任何兼容的阅读器会如何解析该长度;表示子消息的长度为18107261字节;大多数读者在发现缺少18107250个字节时都会拒绝。Python版本(即您正在使用的版本)可能会一直读到最后,但在我看来,这将是该实现中的一个bug@我也不明白这一点。为了尝试您的建议,即只读取数组的末尾,我添加了一些随机字符。只需要一个额外的字符就会产生错误。提示:-坚持你的十六进制,它会解释所有的错误。另外:我认为你的数据是无效的-所以,是的,我在这里有点同意你。。。有没有可能你破坏了数据,没有给出真正的十六进制?特别是通过使用字符串函数?FWIW:fd 96 d1 08在此上下文中指定子消息的长度为18107261,这在@Marc gravel good work中是非常错误的