protocol buffers 使用

protocol buffers简单的解释就是,类似与json,xml储存数据的一种格式。

优点:空间效率高。缺点:二进制格式,不易阅读。

release地址,这里要说明一下,找开源不要去github直接下载最新的,而是要下载release版本,因为release稳定性高些:https://github.com/protocolbuffers/protobuf/releases

编译:cd $(OPENSOURCE_LIB_BUILD_PWD) && ./configure --prefix=$(OPENSOURCE_INSTALL_PWD) --host=$(CROSS_COMPILE) && make clean && make && make install

我非常纳闷的问题,同一个源码3.13,以前可以正常编译,现在出现了错误:

##################提示以下错误,以前可以正常编译,但出现下面错误,不编译shared文件即可。
##################./.libs/libprotoc.so: error: undefined reference to 'scc_info_FileDescriptorProto_google_2fprotobuf_2fdescriptor_2eproto'
##################./.libs/libprotoc.so: error: undefined reference to 'descriptor_table_google_2fprotobuf_2fdescriptor_2eproto'

现在取消动态库编译,避免这个问题:

./autogen.sh && ./configure --prefix=$(OPENSOURCE_INSTALL_PWD) --host=$(CROSS_COMPILE) --enable-shared=no CC=$(CROSS_COMPILE)-gcc CXX=$(CROSS_COMPILE)-g++

make

make install 

或者使用cmake,我使用cmake也可以看到他并没有生成动态库!!!:

cmake . -Dprotobuf_BUILD_TESTS=OFF -DCMAKE_INSTALL_PREFIX=$(OPENSOURCE_INSTALL_PWD) -DCMAKE_CXX_COMPILER=$(CROSS_COMPILE)-g++ -DCMAKE_C_COMPILER=$(CROSS_COMPILE)-gcc

make

make install

使用例子:

先写一个:xxx.proto文件,这个文件用于生成.cc和.h文件,以便我们调用API。

surTeacherInfMsg.proto内容如下:

//备注:
//1.syntax表示指定版本,我们用最新的版本proto3。
//2.package定义一个域名,在c++语言调用时需要加上:surTeacherwork::xxx。
//3.message定义一个结构体,用于结构体转数组和数组转结构体。
//4.required必填内容,proto3废除。
/*5.optional可选,proto3也可不要,如果添加optional,在执行protoc命令时需要加
--experimental_allow_proto3_optional。*/
//6.在proto3中取消默认值,默认值为0,或空。
/*7.结构体中,每个成员变量都有一个编号1,2,3,4... 很重要。PROTOBUF是通过这个编号来编解码的,
如果编码和解码的结构体对应编号和类型不一致,就会导致错误。teacherInfNewDef和teacherInfDef
中"int32 id = 1; optional int32 age = 2; optional string add = 3; string res7 = 
4;"是一致的,teacherInfNewDef新增了"optional float res5 = 5; int32 res6 = 6;"内容。
teacherInfDef可以解析teacherInfNewDef内容,而teacherInfNewDef解析teacherInfDef内容时,
res5和res6为0,字符串为空。*/
8.string是字符串,如果要用到二进制数组,使用bytes
//这里的message定义结构体

syntax = "proto3";
package surTeacherwork;

message teacherInfDef
{
    //required is not used in proto3
    int32 id = 1;
    optional int32 age = 2;
    optional string add = 3;
    string res7 = 4;
}

message teacherListInfDef
{
    int32 buflen = 1;
    repeated teacherInfDef teacher = 2;
}

message teacherInfNewDef
{
    //required is not used in proto3
    int32 id = 1;
    optional int32 age = 2;
    optional string add = 3;
    string res7 = 4;
    optional float res5 = 5;
    int32 res6 = 6;
}

message teacherListInfNewDef
{
    int32 buflen = 1;
    repeated teacherInfNewDef teacher = 2;
}

数据类型参考:(三)ProtoBuf数据类型 - 比特边界 - 博客园

第二个文件:surStudentInfMsg.proto,里面有bytes的用法

syntax = "proto3";
package surwork;

enum Direction {
	START = 0;
	EAST = 1;
	SOUTH = 2;
	WEST = 3;
	NORTH = 4;
};

message studentInfDef
{
    //required is not used in proto3
    int32 id = 1;
    int32 age = 2;
    string add = 3;
    Direction dir = 4;
    optional string res1 = 5;
    //string cannot save bin string, bytes can do that.
    optional bytes res2 = 6;
    optional int32 res3 = 7;
    optional int32 res4 = 8;
    float res5 = 9;
}

message studentListInfDef
{
    //string tbname;
    int32 buflen = 1;
    repeated studentInfDef student = 2;
}

生成.cc文件:

protoc --experimental_allow_proto3_optional -I=. --cpp_out=. surTeacherInfMsg.proto;

protoc --experimental_allow_proto3_optional -I=. --cpp_out=. surStudentInfMsg.proto;

使用:

//备注:
//1.surTeacherwork就是域名
//2.teacherListInfDef时proto生成的类。
/*3.新老版本公共的参数,变量类型和序列号要保持一致!int型变量名"id"序列号都要为1,
string型变量"add"序列号都要为3。参考proto设计*/
//老版本编码(SerializeToString),新版本解码(ParseFromString)

void testProtoBuff1()
{
    //zlibCompressClass tempCompressWork = zlibCompressClass(10 * 1024 * 1024);
    zlibCompressClass tempCompressWork = zlibCompressClass();
    surwork::studentListInfDef saveinf;
    surwork::studentListInfDef parseinf;
    surwork::studentInfDef *tmpstud;
    string mypackstr, zlibencode, zlibuncode;
    timerc tnowg;
    char mytmps[4];// = {(char)0x1, (char)0x2, (char)0x3, (char)0x4, (char)0xdf};
    int i;
    printfdbg("begin");
    for (i = 0; i < STUDENT_BUF_MAX_LEN; i++)
    {
        tmpstud = saveinf.add_student();
        tmpstud->set_id(i);
        tmpstud->set_age(i % 2);
        tmpstud->set_dir((surwork::Direction)(i % (surwork::NORTH + 1)));
        tmpstud->set_res1("jfdfjk");
        for(int j = 0; j < 4; j++)
        {
            mytmps[j] = (i >> (j * 8)) & 0xff;
        }
        tmpstud->set_res2(mytmps, sizeof(mytmps));
        tmpstud->set_res3(2);
    }
    printfdbg("generate finish: used time = %fs", tnowg.ints());
    tnowg.begin();
    saveinf.set_buflen(STUDENT_BUF_MAX_LEN);
    if (!saveinf.SerializeToString(&mypackstr))
    {
        printfdbg("");
        return;
    }

    printfdbg("%ld", mypackstr.length());
    printfdbg("to stirng: used time = %fs", tnowg.ints());
    tnowg.begin();

    if(tempCompressWork.compress(mypackstr, zlibencode))
    {
        printfdbg("");
        return;
    }

    printfdbg("%ld", zlibencode.length());
    printfdbg("compress: used time = %fs", tnowg.ints());
    tnowg.begin();

    if(tempCompressWork.umcompress(zlibencode, zlibuncode))
    {
        printfdbg("");
        return;
    }

    printfdbg("%ld", zlibuncode.length());
    printfdbg("uncompress: used time = %fs", tnowg.ints());
    tnowg.begin();

    if (!parseinf.ParseFromString(zlibuncode))
    {
        printfdbg("");
        return;
    }


    printfdbg("%d, %d, %.3f", parseinf.buflen(), parseinf.student_size(), tnowg.ints());
    printfdbg("to inf: used time = %fs", tnowg.ints());
    tnowg.begin();
    for (int i = 0; i < parseinf.student_size(); i++)
    {
        surwork::studentInfDef tmpsifget = parseinf.student(i);
        string myresstr = tmpsifget.res2();
        // printfdbg("%d,%d,%s,%d,%s,%s,%d,%d,%f", tmpsifget.id(), tmpsifget.age(), tmpsifget.add().c_str(),
        //           tmpsifget.dir(), tmpsifget.res1().c_str(), tmpsifget.res2().c_str(),
        //           tmpsifget.res3(), tmpsifget.res4(), tmpsifget.res5());
        // printfdbg("0x%02x,0x%02x,0x%02x,0x%02x,%ld", myresstr[0], myresstr[1], myresstr[2], myresstr[3],
        //           myresstr.length());
    }
}

void testCompatible1()
{
    surTeacherwork::teacherListInfDef savebuf;
    surTeacherwork::teacherInfDef *saveinf;
    surTeacherwork::teacherListInfNewDef parsebuf;
    surTeacherwork::teacherInfNewDef parseinf;
    int i;
    string packstr;
    timerc ctnow;
    for (i = 0; i < 10; i++)
    {
        saveinf = savebuf.add_teacher();
        saveinf->set_id(i);
        saveinf->set_add("sub_" + to_string(i));
        saveinf->set_res7(to_string(i + 2));
    }

    savebuf.set_buflen(savebuf.teacher_size());
    if (!savebuf.SerializeToString(&packstr))
    {
        printfdbg("");
        return;
    }

    if (!parsebuf.ParseFromString(packstr))
    {
        printfdbg("");
        return;
    }

    printfdbg("%d, %d, %.3f", parsebuf.buflen(), parsebuf.teacher_size(), ctnow.ints());
    for (i = 0; i < parsebuf.teacher_size(); i++)
    {
        parseinf = parsebuf.teacher(i);
        printfdbg("%d,%d,%s,%.2f,%d,%s", parseinf.id(), parseinf.age(), parseinf.add().c_str(), parseinf.res5(), 
            parseinf.res6(), parseinf.res7().c_str());
    }
}

//新版本编码(SerializeToString),老版本解码(ParseFromString)
void testCompatible2()
{
    surTeacherwork::teacherListInfNewDef savebuf;
    surTeacherwork::teacherInfNewDef *saveinf;
    surTeacherwork::teacherListInfDef parsebuf;
    surTeacherwork::teacherInfDef parseinf;
    int i;
    string packstr;
    timerc ctnow;
    for (i = 0; i < 10; i++)
    {
        saveinf = savebuf.add_teacher();
        saveinf->set_id(i);
        saveinf->set_add("ab_" + to_string(i));
        saveinf->set_res5(((float)i * 123 - 42) * 0.124);
        saveinf->set_res6(i+2);
        saveinf->set_res7(to_string(i + 2));
    }

    savebuf.set_buflen(savebuf.teacher_size());
    if (!savebuf.SerializeToString(&packstr))
    {
        printfdbg("");
        return;
    }

    if (!parsebuf.ParseFromString(packstr))
    {
        printfdbg("");
        return;
    }

    printfdbg("%d, %d, %.3f", parsebuf.buflen(), parsebuf.teacher_size(), ctnow.ints());
    for (i = 0; i < parsebuf.teacher_size(); i++)
    {
        parseinf = parsebuf.teacher(i);
        printfdbg("%d,%d,%s,%s", parseinf.id(), parseinf.age(), parseinf.add().c_str(), parseinf.res7().c_str());
    }
}

int main()
{
    signal(SIGABRT, dump);
    signal(SIGBUS, dump);
    signal(SIGSEGV, dump);
    testProtoBuff1();
    testCompatible1();
    testCompatible2();
    return 0;
}

打印结果:

[2020-11-2 15:11:4.899][dbg][testCompatible1,155]10, 10, 0.000
[2020-11-2 15:11:4.899][dbg][testCompatible1,159]0,0,sub_0,0.00,0,2
[2020-11-2 15:11:4.899][dbg][testCompatible1,159]1,0,sub_1,0.00,0,3
[2020-11-2 15:11:4.899][dbg][testCompatible1,159]2,0,sub_2,0.00,0,4
[2020-11-2 15:11:4.899][dbg][testCompatible1,159]3,0,sub_3,0.00,0,5
[2020-11-2 15:11:4.899][dbg][testCompatible1,159]4,0,sub_4,0.00,0,6
[2020-11-2 15:11:4.899][dbg][testCompatible1,159]5,0,sub_5,0.00,0,7
[2020-11-2 15:11:4.899][dbg][testCompatible1,159]6,0,sub_6,0.00,0,8
[2020-11-2 15:11:4.899][dbg][testCompatible1,159]7,0,sub_7,0.00,0,9
[2020-11-2 15:11:4.899][dbg][testCompatible1,159]8,0,sub_8,0.00,0,10
[2020-11-2 15:11:4.899][dbg][testCompatible1,159]9,0,sub_9,0.00,0,11
[2020-11-2 15:11:4.901][dbg][testCompatible2,196]10, 10, 0.000
[2020-11-2 15:11:4.901][dbg][testCompatible2,200]0,0,ab_0,2
[2020-11-2 15:11:4.901][dbg][testCompatible2,200]1,0,ab_1,3
[2020-11-2 15:11:4.901][dbg][testCompatible2,200]2,0,ab_2,4
[2020-11-2 15:11:4.901][dbg][testCompatible2,200]3,0,ab_3,5
[2020-11-2 15:11:4.901][dbg][testCompatible2,200]4,0,ab_4,6
[2020-11-2 15:11:4.901][dbg][testCompatible2,200]5,0,ab_5,7
[2020-11-2 15:11:4.901][dbg][testCompatible2,200]6,0,ab_6,8
[2020-11-2 15:11:4.901][dbg][testCompatible2,200]7,0,ab_7,9
[2020-11-2 15:11:4.901][dbg][testCompatible2,200]8,0,ab_8,10
[2020-11-2 15:11:4.901][dbg][testCompatible2,200]9,0,ab_9,11


版权声明:本文为hxchuan000原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。