魏县网站制作,郑州网站模板哪里有,ps做网站首页设计教程,明快网站设计0x01 protobuf的基本概念 protobuf通过定义.proto文件来描述数据的结构。.proto文件中用Message所表示所需要序列化的数据的格式。Message由field组成#xff0c;Field类似JAVA或者C中成员变量#xff0c;通常一个field的定义包含修饰符、类型、名称…0x01 protobuf的基本概念 protobuf通过定义.proto文件来描述数据的结构。.proto文件中用Message所表示所需要序列化的数据的格式。Message由field组成Field类似JAVA或者C中成员变量通常一个field的定义包含修饰符、类型、名称和ID。下面看一个简单的.proto文件的例子 package testInfo;
message Chats
{optional string content1 1;required int32 content2 2;message EmbMsg{optional string a 1;}repeated EmbMsg a 3;
}然后利用protoc工具生成.h和.cpp文件并且编写代码 testInfo::Chats chatTest;chatTest.set_content1(hello);chatTest.set_content2(32);testInfo::Chats::EmbMsg *pMsg chatTest.add_a();pMsg-set_a(aaaa);pMsg chatTest.add_a();pMsg-set_a(bbb);std::string outputStr;chatTest.SerializeToString(outputStr);printf(str %s, outputStr.c_str());得到十六进制流数据为 0x00DE94C8 0a 05 68 65 6c 6c 6f 10 20 1a 06 0a 04 61 61 61 ..hello. ....aaa
0x00DE94D8 61 1a 05 0a 03 62 62 62 0x02 protobuf流的反解析 2.1 Varint编码 Protobuf的二进制使用Varint编码。Varint 是一种紧凑的表示数字的方法。它用一个或多个字节来表示一个数字值越小的数字使用越少的字节数。这能减少用来表示数字的字节数。 Varint 中的每个 byte 的最高位 bit 有特殊的含义如果该位为 1表示后续的 byte 也是该数字的一部分如果该位为 0则结束。其他的 7 个 bit 都用来表示数字。因此小于 128 的数字都可以用一个 byte 表示。 例如十六进制流里面其中两个字节0x95 0x01则其转换运算为(0x95 0x7F) | (0x01 0x7) 0x5 | 0x80 0x95。
若其中四个字节0x9D 0xF4 0xC1 0xCB 0x05,则其转换运算为
(0x9D 0x7F) | (0xF4 0x7F)7 | (0xC1 0x7F)E | (0xCB 0x7F)0x15 | 050x1C 1D | 3A00 | 104000 | 9600000 | 50000000 59707A1D 2.2 数值类型 Protobuf经序列化后以二进制数据流形式存储这个数据流是一系列key-Value对。Key用来标识具体的Field在解包的时候Protobuf根据 Key 就可以知道相应的 Value 应该对应于消息中的哪一个 Field。 Key 的定义如下
(field_number 3) | wire_type
Key由两部分组成。第一部分是 field_number比如消息chatTest.content1中 的 field_number 为 1。第二部分为 wire_type。表示 Value 的传输类型。Wire Type 可能的类型如下表所示 typeMeaningUsed For0Varintint32, int64, uint32, uint64, sint32, sint64, bool, enum164-bitfixed64, sfixed64, double2Length-delimistring, bytes, embedded messages, packed repeated fields3Start groupGroups (deprecated)4End groupGroups (deprecated)532-bit fixed32, sfixed32, float 以上面生成的十六进制流我们可以开始分析required和optional不会有任何字节来表示这个修饰符。
repeated会存在相同的field_number。 0a 050A - field_num1, type2; 05 - 代表字符串长度05 68 65 6c 6c 6f- hello 10 2010-field_num2, type0; 20-value0x20; 1a 06 0a 04 61 61 61 61 1a 05 0a 03 62 62 621a-field_num3, type2; 06-结构体长度06
0a-field_num1,type2;
04-字符串长度04
61 61 61 61 -valueaaaa
1a-field_num3, type2; 05-结构体长度05
0a-field_num1,type2;
03-字符串长度03
61 61 61 61 -valuebbb 2.3 protoc 进行反序列化 上面的步骤是手动解析的过程而利用google提供的工具可以帮助我们自动化的解析以上过程在面对复杂的protobuf结构的时候能达到事半功倍的效果。按下面步骤来做
首先配置java环境
其次安装jython,这里
然后编写python脚本protobuf.py import subprocess
def decode(data):process subprocess.Popen([rD:\protobuf\protoc.exe, --decode_raw],stdinsubprocess.PIPE,stdoutsubprocess.PIPE,stderrsubprocess.PIPE)output error Nonetry:output, error process.communicate(data)except OSError:passfinally:if process.poll() ! 0:process.wait()return outputf open(rD:\testprotobuf.bin, rb)
data f.read()
print data:/n,decode(data)
f.close()其中testprotobuf.bin是我们的protobuf流文件。 最后运行脚本 C:\Users\Administratorcd C:\jython2.7.0C:\jython2.7.0java -jar jython.jar D:\task\qq-ups\protobuf.py
data:/n 1: hello
2: 32
3 {1: aaaa
}
3 {1: bbb
}利用反序列化的结构来推测.proto的message的结构及每个字段的含义就能达到protobuf流反解析的目的了。