1 Protobuf
简介
1.1 What is
Protobuf
?
protobuf也叫protocol buffer是google 的
一种数据交换的格式
,它
独立于语言,独立于平台
。google 提供了多种语言的实现:java、c#、c++、go 和 python,每一种实现都包含了相应语言的编译器以及库文件。
由于它是一种二进制的格式,比使用 xml 、json进行数据交换快许多。可以把它用于分布式应用之间的数据通信或者异构环境下的数据交换。作为一种效率和兼容性都很优秀的二进制数据传输格式,可以用于诸如网络传输、配置文件、数据存储等诸多领域。
1.2
Protobuf
的优缺点
1.2.1 优点
- 性能好/效率高
- 代码生成机制
- 支持“向后兼容”和“向前兼容”
- 支持多种编程语言
1.2.2 缺点
- 应用不够广(相比xml和json)
- 二进制格式导致可读性差
- 缺乏自描述
为什么protobuf的性能比json高呢?这就得从protobuf的压缩原理来分析了。
图上这个json长度为27字节,但是为了表示这个数据结构,它用了9个字节(就是那些大括号、引号、冒号之类的,他们是白白多出来的)来表示那些额外添加的无意义数据。
msgpack
的优化在图上展示的也比较清楚了,省去了特殊符号,用特定编码对各种类型进行定义,比如上图的A7,其中前四个bit A就是表示str的编码,而且它表示这个str的长度只用半个字节就可以表示了,也就是后面的7,因此A7的意思就是表示后面是一个7字节长度的string。
有的同学就会问了,对于长度大于15(二进制1111)的string怎么表示呢?这就要看messagepack的压缩原理了。(
MessagePack简介及使用 – 简书
)
2 Protobuf
安装
2.1 Ubuntu
环境搭建
github源代码下载地址:
GitHub – protocolbuffers/protobuf: Protocol Buffers – Google’s data interchange format
源码包中的src/README.md, 有详细的安装说明,安装过程如下:
1、解压压缩包:
unzip protobuf-master.zip
2、进入解压后的文件夹:
cd protobuf-master
3、安装所需工具:
sudo apt-get install autoconf automake libtool curl make g++ unzip
4、自动生成configure配置文件:
./autogen.sh
5、配置环境:
./configure
6、编译源代码(时间比较长):
make
7、安装:
sudo make install
8、刷新动态库:
sudo ldconfig
2.2 protobuf-c
插件安装
如果想将.proto编译成.c文件的话,需要装protobuf-c的插件,步骤如下:
The steps of installing protobuf-c plugin are as follows:
- sudo apt install git(如果已安装git,则跳过);
-
git clone
GitHub – protobuf-c/protobuf-c: Protocol Buffers implementation in C
; - sudo ./configure && make && make install;
编译命令 protoc --c_out=. example.proto
3 Protobuf
基本语法
基本语法见
Protobuf语言指南 – dkcndk – 博客园
3.1
三个关键字required、optional、repeated
-
required关键字
顾名思义,就是必须的意思,数据发送方和接收方都必须处理这个字段,不然还怎么通讯呢?
字面意思是可选的意思,具体protobuf里面怎么处理这个字段呢,就是protobuf处理的时候另外加了一个bool的变量,用来标记这个optional字段是否有值,发送方在发送的时候,如果这个字段有值,那么就给bool变量标记为true,否则就标记为false,接收方在收到这个字段的同时,也会收到发送方同时发送的bool变量,拿着bool变量就知道这个字段是否有值了,这就是option的意思。
这也就是他们说的所谓平滑升级,无非就是个兼容的意思。其实和传输参数的时候,给出数组地址和数组数量是一个道理。
字面意思大概是重复的意思,其实protobuf处理这个字段的时候,也是optional字段一样,另外加了一个count计数变量,用于标明这个字段有多少个,这样发送方发送的时候,同时发送了count计数变量和这个字段的起始地址,接收方在接受到数据之后,按照count来解析对应的数据即可。
4
代码案例
4.1 c
4.1.1 编码(encoding)
① 创建一个简单文件:amessage.proto,内容如下
// [START declaration]
syntax = "proto3";
// [END declaration]
message AMessage
{
int32 a = 1;
int32 b = 2;
}
② 通过命令行产生相应的.h和.c源文件。
protoc-c –c_out=. amessage.proto
③ main函数如下
#include<stdio.h>
#include<stdlib.h>
#include"amessage.pb-c.h"
#define myfilename "encoding.txt"
int main (int argc,const char* argv[])
{
AMessage msg = AMESSAGE__INIT;// AMessage
void* buf; // Buffer to storeserialized data
unsigned int len; // Length of serialized data
if(argc != 2 && argc != 3){ // Allow one or twointegers
fprintf(stderr,"usage:amessage a [b]\n");
return 1;
}
msg.a = atoi(argv[1]);
if(argc == 3){
msg.b = atoi(argv[2]);
printf("msg.b=%d\n",msg.b);
}
len = amessage__get_packed_size(&msg);
buf = malloc(len);
amessage__pack(&msg, buf);
FILE *pf = fopen(myfilename, "wb");
fprintf(stderr,"Writing %d serialized bytes\n",len);// See the length of message
fwrite(buf, len, 1, pf);
free(buf);// Free theallocated serialized buffer
fclose(pf);
return 0;
}
④ gcc编译源码,生成a.out
⑤ 执行a.out,生成encoding.txt