为什么要使用protobuf
结构化数据的几种方式:
1.raw in-memory data structures:二进制存储,但是脆弱,因为读这些数据的代码必须要以同样的内存布局来编译
2.以特定方式编码:比如12:3:-23:67来编码4个整数,语法分析耗时,只能用于简单的数据
3.XML:人类可读,多种语言适配,但是较为复杂
protobuf:灵活、效率高、可扩展
简单
比xml要小3到10倍,proto文件被编译成bin二进制文件
比xml要快20到100倍
结构更加清晰,不会产生歧义
生成数据操作类更加容易,编程更加容易上手,访问接口代码基本都是自动生产
简单使用
https://github.com/protobuf-c/protobuf-c/wiki/Examples
https://developers.google.com/protocol-buffers/docs/cpptutorial
package
防止命名冲突,相当于命名空间
amessage.proto文件
message AMessage {
required int32 a=1;
optional int32 b=2;
}
生成.h 和.c文件
protoc-c --c_out=. amessage.proto
链接
-lprotobuf-c
Serialize/pack
construct message :AMESSAGE_INIT
b是否存在(optional才有):msg.has_b
获得packed data的长度:amessage_get_packed_size(&msg)
serializes the message:amessage__pack(&msg, buf)
/*
构建一个message,并从参数获得值,获得长度,pack,写入缓冲区
*/
#include <stdio.h>
#include <stdlib.h>
#include "amessage.pb-c.h"
int main (int argc, const char * argv[])
{
// 1.构建msg
AMessage msg = AMESSAGE__INIT; // AMessage
void *buf; // Buffer to store serialized data
unsigned len; // Length of serialized data
if (argc != 2 && argc != 3)
{ // Allow one or two integers
fprintf(stderr,"usage: amessage a [b]\n");
return 1;
}
// 2.赋值
msg.a = atoi(argv[1]);
if (argc == 3) { msg.has_b = 1; msg.b = atoi(argv[2]); }
// 3.获得长度
len = amessage__get_packed_size(&msg);
buf = malloc(len);
// 4.pack
amessage__pack(&msg,buf); //pack
fprintf(stderr,"Writing %d serialized bytes\n",len); // See the length of message
fwrite(buf,len,1,stdout); // Write to stdout to allow direct command line piping
free(buf); // Free the allocated serialized buffer
return 0;
}
deserialize/unpack
unpack(先AMessage *msg;):msg = amessage__unpack(NULL, msg_len, buf)
free the unpacked message:amessage__free_unpacked(msg, NULL);
Repeated
message CMessage {
repeated int32 c=1;
}
c的个数:msg.n_c
访问c数组:msg.c[i]
Submessages
message Submessage {
required int32 value=1;
}
message EMessage {
required Submessage a=1;
optional Submessage b=2;
}
serialize/pack
optional submessages没有has_,如果指针不为空,默认有值
EMessage msg = EMESSAGE__INIT; // EMESSAGE
Submessage sub1 = SUBMESSAGE__INIT; // SUBMESSAGE A
Submessage sub2 = SUBMESSAGE__INIT; // SUBMESSAGE B
sub1.value = atoi (argv[1]);
msg.a = &sub1; // 存储的是指向submessage的指针
sub2.value = atoi (argv[2]);
msg.b = &sub2;
len = emessage__get_packed_size (&msg); // This is the calculated packing length
buf = malloc (len); // Allocate memory
emessage__pack (&msg, buf); // Pack msg, including submessages
eserialize/unpack
EMessage *msg; // EMessage using submessages
Submessage *sub1,*sub2;// Submessages
msg = emessage__unpack(NULL,i,buf);
sub1 = msg->a;
sub2 = msg->b;
emessage__free_unpacked(msg,NULL);
Repeated Submessages
message Submessage {
required int32 value=1;
}
message FMessage {
repeated Submessage a=1;
}
pack
FMessage msg = FMESSAGE__INIT;
Submessage **subs;
for (i = 1; i < argc; i++)
{
subs[i-1] = malloc (sizeof (Submessage));
submessage__init (subs[i-1]);
subs[i-1]->value = atoi(argv[i]);
}
msg.n_a = argc-1; // a的个数
msg.a = subs; //subs赋给a,a是指针的数组
len = fmessage__get_packed_size (&msg); // This is the calculated packing length
buf = malloc (len); // Allocate memory
fmessage__pack (&msg, buf); // Pack msg, including submessages
unpack
FMessage *msg;
msg = fmessage__unpack(NULL,i,buf);
fmessage__free_unpacked(msg,NULL);