一.简介
protobuf是一种google开源的序列化,反序列化工具。
该工具由protoc-c应用程序
和protobuf-c动态库
两部分组成。
二.使用步骤
(1). 提供自定义的xxx.proto文件
,来定义你要序列化和反序列化的类型.
(2). 通过proto-c应用程序,为xxx.proto生成相应的xxx.pb-c.h,xxx.pb-c.c这样的代码文件
.
生成的代码文件包含了xxx.proto类型的定义,并提供了类型序列化,反向序列化的功能实现.
(3). 现在应用程序需要对xxx.proto中类型执行序列化或反序列化处理时,只需编译时,一起编译xxx.pb-c.c源文件
,且编译链接和运行链接时,链接到protobuf-c动态库.这样在应用程序代码中就可引用xxx.pb-c.h中的类型,并调用类型的序列化,反向序列化方法实现类型实例的序列化处理,反向序列化处理.
三.应用场景
protobuf-c 可广泛应用于以下场景:
嵌入式系统:由于其小体积和跨平台特性,非常适合在资源有限的设备上使用。
网络通信:通过配合RPC框架,实现高效的数据交换。
数据持久化:将结构化数据序列化到磁盘,然后在程序启动时进行反序列化,以节省内存和提高读写速度。
四.使用方法
1. windows使用方法
下载protoc.exe,protoc.jar
https://download.csdn.net/download/qq_32348883/89750388
- 将
proto文件, protoc.exe, protoc.jar
放在同一个文件夹中; - 执行
java -jar protoc.jar your.proto
; - 编写调用接口测试用的demo;
- 将
protobuf_c.c, protobuf_c.h
加入工程一起编译; - 运行。
C接口使用例子
#include "MyProto.h"
static const char hexdig[] = "0123456789abcdef";
static void log_hex(const char* tag, unsigned char* data, int len)
{
char msg[50], *ptr;
int i;
ptr = msg;
printf("%s\r\n", tag);
for(i=0; i<len; i++) {
*ptr++ = hexdig[0x0f & (data[i] >> 4)];
*ptr++ = hexdig[0x0f & data[i]];
if ((i & 0x0f) == 0x0f) {
*ptr = '\0';
ptr = msg;
printf("%s\r\n", msg);
} else {
*ptr++ = ' ';
}
}
if (i & 0x0f) {
*ptr = '\0';
printf("%s\r\n", msg);
}
}
#define PB_STR(str) {(uint8_t*)str, (uint32_t)strlen(str)}
int main(int argc, char *argv[])
{
uint8_t* data;
int out_len;
{
MyType mytype;
MyProto myproto;
MyType_init(&mytype);
MyType_set_i32(&mytype, 123);
MyProto_init(&myproto);
MyProto_set_i32(&myproto, 456);
MyProto_set_i64(&myproto, 789);
pb_string str = PB_STR("hello");
MyProto_set_str(&myproto, &str);
MyProto_set_msg(&myproto, &mytype);
data = MyProto_to_byte_array(&myproto, &out_len);
log_hex("", data, out_len);
}
{
MyProto myproto;
MyProto_init(&myproto);
MyProto_from_byte_array(&myproto, data, out_len);
printf("%.*s", myproto.str.size, myproto.str.data);
}
return a.exec();
}
2 linux使用方法
1部分–编译protobuf-c
下载
https://github.com/protobuf-c/protobuf-c
(1)交叉编译protobuf-c
首先在protobuf-c目录下使用make clean命令清除我们之前编译得到的东西:
输入如下命令生成交叉编译的Makefile文件:
./configure --host=arm-linux-gnueabihf CC=/home/book/ToolChain/gcc-arm-linux-gnueabihf-6.2.1/bin/arm-linux-gnueabihf-gcc CXX=/home/book/ToolChain/gcc-arm-linux-gnueabihf-6.2.1/bin/arm-linux-gnueabihf-g++ --disable-protoc --prefix=$PWD/tmp
这个命令似乎很长,但并不难,只是加了几个配置参数。这些配置参数怎么看?我们可以输入./configure --help命令来查看支持的配置:
下面我们依次来分析上面那个很长的命令:
-
–host=arm-linux-gnueabihf:表明了我们最终可执行文件运行的环境。
-
CC=/home/book/ToolChain/gcc-arm-linux-gnueabihf-6.2.1/bin/arm-linux-gnueabihf-gcc:这是指定我们的交叉编译工具arm-linux-gnueabihf-gcc,这里直接给出绝对路径。
-
CXX=/home/book/ToolChain/gcc-arm-linux-gnueabihf-6.2.1/bin/arm-linux-gnueabihf-g++:这是指定我们的交叉编译工具arm-linux-gnueabihf-g++,这里直接给出绝对路径。
-
–disable-protoc:不使用protoc,前面我们也说了protoc工具把.proto文件生成对应的C源、头文件的过程是与平台无关的,所以这里不需要使用,除非我们想在我们的开发板上使用protoc,但这反而增加麻烦,不推荐直接在开发板上用。
-
–prefix=$PWD/tmp:指定安装的路径。表明安装路径在当前路径下的tmp文件夹中。
执行完这个命令之后就得到了交叉编译的Makefile文件,然后依次输入如下命令进行编译、安装:
make
make install
此时就在当前目录的tmp文件夹下生成了arm版本的相关库文件:
其中我们比较重要的就是libprotobuf-c.so这个动态库了,我们可以使用file或者readelf工具查看其是不是arm格式的:
2部分–使用protobuf-c
我们自定义一个.proto来创建我们的协议数据,然后使用protoc-c工具编译生成C代码,有两个文件:一个头文件、一个源文件。
例如我们创建一个student.proto文件
:
syntax = "proto2";
message Student
{
required string name = 1;
required uint32 num = 2;
required uint32 c_score = 3;
}
使用protoc-c工具工具编译student.proto文件:
protoc --c_out=. student.proto
编写我们的student.c测试demo:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "student.pb-c.h"
int main(void)
{
Student pack_stu = {0};
uint8_t buffer[512] = {0};
Student *unpack_stu = NULL;
size_t len = 0;
student__init(&pack_stu);
/* 组包 */
pack_stu.name = "ZhengN";
pack_stu.num = 88;
pack_stu.c_score = 90;
len = student__pack(&pack_stu, buffer);
printf("len = %ld\n",len);
/* 解包 */
unpack_stu = student__unpack(NULL, len, buffer);
printf("unpack_stu.name = %s\n", unpack_stu->name);
printf("unpack_stu.num = %d\n", unpack_stu->num);
printf("unpack_stu.c_score = %d\n", unpack_stu->c_score);
student__free_unpacked(unpack_stu, NULL);
return 0;
}
demo很简单,组包就是构造一个协议数据结构体,调用pack组包接口往buffer中扔数据;解包正好是反过来,从buffer中拿数据放到结构体里。
此时我们工程的文件有:
编译运行:
arm-linux-gnueabihf-gcc student.c student.pb-c.c -o student -I /home/book/git_clone/protobuf-c/tmp/include -L /home/book/git_clone/protobuf-c/tmp/lib -lprotobuf-c
编译没问题的话就可以生成我们的可执行文件student:
同样的,我们可以看一下student可执行文件的运行环境:
可见,是可运行在我们的arm开发板的。
运行出现如下错误:
这是因为不能找到共享库文件libprotobuf-c.so1,加载失败。
解决方法有两种:第一种就是把这个库文件拷贝至系统库默认搜索路径下;第二种就是把当前路径增加为动态库的搜索路径
。
这里我们选择第二种方法:我们把libprotobuf-c.so、libprotobuf-c.so1也传到板子上,放在student同目录下
。然后输入如下命令把当前路径增加为动态库的搜索路径:
export LD_LIBRARY_PATH=./:$LD_LIBRARY_PATH
然后运行: