介绍
Protocol Buffers,是Google公司开发的一种数据描述语言,类似于XML能够将结构化数据序列化,可用于数据存储、通信协议等方面。它不依赖于语言和平台并且可扩展性极强。
同XML相比,Protocol buffers在序列化结构化数据方面有许多优点:
1. 更简单
2. 数据描述文件只需原来的1/10至1/3
3. 解析速度是原来的20倍至100倍
4. 减少了二义性
5. 生成了更容易在编程中使用的数据访问
6.支持多种编程语言
(转自百度百科)
- 完整代码放到我的github下了
安装
这里我使用的是 protobuf-c,在安装 protobuf-c 之前需要安装 protobuf 。
安装protobuf
首先安装依赖 sudo apt-get install autoconf automake libtool curl make g++ unzip
git clone https://github.com/protocolbuffers/protobuf.git
cd protobuf
git submodule update --init --recursive
./autogen.sh
./configure
make
make check # make check 失败的话没关系,继续下面的安装
sudo make install
sudo ldconfig
安装protobuf-c
首先安装依赖sudo apt-get install pkg-config pkgconf
git clone https://github.com/protobuf-c/protobuf-c.git
./autogen.sh && ./configure && make && make install
到这里就已经安装好 protobuf 和 protobuf-c
使用protobuf-c
编辑文件student.proto
这里用的是proto2
(建议新手直接上 proto3
)
这里以 student 为例子
syntax = "proto2";
message Student {
optional string name = 1;
}
命令protoc --c_out=. student.proto
生成.c
和.h
文件 student.pb-c.c
student.pb-c.h
不要太关注下面的两个文件
- 下面是生成的
student.pb-c.h
/* Generated by the protocol buffer compiler. DO NOT EDIT! */
/* Generated from: student.proto */
#ifndef PROTOBUF_C_student_2eproto__INCLUDED
#define PROTOBUF_C_student_2eproto__INCLUDED
#include
PROTOBUF_C__BEGIN_DECLS
#if PROTOBUF_C_VERSION_NUMBER < 1000000
# error This file was generated by a newer version of protoc-c which is incompatible with your libprotobuf-c headers. Please update your headers.
#elif 1003003 < PROTOBUF_C_MIN_COMPILER_VERSION
# error This file was generated by an older version of protoc-c which is incompatible with your libprotobuf-c headers. Please regenerate this file with a newer version of protoc-c.
#endif
typedef struct _Student Student;
/* --- enums --- */
/* --- messages --- */
struct _Student
{
ProtobufCMessage base;
char *name;
};
#define STUDENT__INIT \
{ PROTOBUF_C_MESSAGE_INIT (&student__descriptor) \
, NULL }
/* Student methods */
void student__init
(Student *message);
size_t student__get_packed_size
(const Student *message);
size_t student__pack
(const Student *message,
uint8_t *out);
size_t student__pack_to_buffer
(const Student *message,
ProtobufCBuffer *buffer);
Student *
student__unpack
(ProtobufCAllocator *allocator,
size_t len,
const uint8_t *data);
void student__free_unpacked
(Student *message,
ProtobufCAllocator *allocator);
/* --- per-message closures --- */
typedef void (*Student_Closure)
(const Student *message,
void *closure_data);
/* --- services --- */
/* --- descriptors --- */
extern const ProtobufCMessageDescriptor student__descriptor;
PROTOBUF_C__END_DECLS
#endif /* PROTOBUF_C_student_2eproto__INCLUDED */
- 下面是生成的
student.pb-c.c
// student.pb-c.c
/* Generated by the protocol buffer compiler. DO NOT EDIT! */
/* Generated from: student.proto */
/* Do not generate deprecated warnings for self */
#ifndef PROTOBUF_C__NO_DEPRECATED
#define PROTOBUF_C__NO_DEPRECATED
#endif
#include "student.pb-c.h"
void student__init
(Student *message)
{
static const Student init_value = STUDENT__INIT;
*message = init_value;
}
size_t student__get_packed_size
(const Student *message)
{
assert(message->base.descriptor == &student__descriptor);
return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message));
}
size_t student__pack
(const Student *message,
uint8_t *out)
{
assert(message->base.descriptor == &student__descriptor);
return protobuf_c_message_pack ((const ProtobufCMessage*)message, out);
}
size_t student__pack_to_buffer
(const Student *message,
ProtobufCBuffer *buffer)
{
assert(message->base.descriptor == &student__descriptor);
return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer);
}
Student *
student__unpack
(ProtobufCAllocator *allocator,
size_t len,
const uint8_t *data)
{
return (Student *)
protobuf_c_message_unpack (&student__descriptor,
allocator, len, data);
}
void student__free_unpacked
(Student *message,
ProtobufCAllocator *allocator)
{
if(!message)
return;
assert(message->base.descriptor == &student__descriptor);
protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator);
}
static const ProtobufCFieldDescriptor student__field_descriptors[1] =
{
{
"name",
1,
PROTOBUF_C_LABEL_OPTIONAL,
PROTOBUF_C_TYPE_STRING,
0, /* quantifier_offset */
offsetof(Student, name),
NULL,
NULL,
0, /* flags */
0,NULL,NULL /* reserved1,reserved2, etc */
},
};
static const unsigned student__field_indices_by_name[] = {
0, /* field[0] = name */
};
static const ProtobufCIntRange student__number_ranges[1 + 1] =
{
{ 1, 0 },
{ 0, 1 }
};
const ProtobufCMessageDescriptor student__descriptor =
{
PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC,
"Student",
"Student",
"Student",
"",
sizeof(Student),
1,
student__field_descriptors,
student__field_indices_by_name,
1, student__number_ranges,
(ProtobufCMessageInit) student__init,
NULL,NULL,NULL /* reserved[123] */
};
在代码里使用
编辑文件 student.c
#include
#include
#include
#include "student.pb-c.h"
#define NAME_LEN 32
int main() {
Student stu = STUDENT__INIT; // 初始化
void *buf = NULL;
unsigned int len;
Student *msg = NULL;
stu.name = (char*)malloc(NAME_LEN);
stu.name = "test";
len = student__get_packed_size(&stu); // 算出大小
printf("size of Student info : %u\n", len);
buf = malloc(len);
student__pack(&stu, buf); // 打包
msg = student__unpack(NULL, len, buf); // 解包
printf("msg name : %s\n", msg->name);
student__free_unpacked(msg, NULL); // 释放空间
free(buf);
return 0;
}
编译
编译 gcc student.c student.pb-c.c -o student -lprotobuf-c
需要连接 protobuf-c 库
输出:
size of Student info : 6
msg name : test
2020.3.2 16:40 广州