Google Protocol Buffer Basics: C++

Google Protocol Buffers是一种序列化数据结构的协议。对于透过管线(pipeline)或存储数据进行通信的程序开发上是很有用的。这个方法包含一个接口描述语言,描述一些数据结构,并提供程序工具根据这些描述产生代码,用于将这些数据结构产生或解析数据流。

C++ Installation - Unix

本文基于Ubuntu实战的直接apt-get就可以了,

$ sudo apt-get install autoconf automake libtool curl make g++ unzip

如果使用其他的操作系统的,请参见 https://github.com/protocolbuffers/protobuf/blob/master/src/README.md 。

构建Protobuf项目

首先创建一个项目文件夹helloproto,接着编写proto/hello.proto文件,当然文件位置、取名随意,但是后缀必须为.proto

.
└── helloproto
├── CMakeLists.txt
├── proto
│   └── hello.proto
├── readpb.cpp
└── writepb.cpp

  1. proto/hello.proto syntax声明版本,package声明C++命名空间,message定义类型。

    syntax = "proto2";
    package helloproto;

    message helloworld{
    required string value = 1;
    }

    .proto文件生成好之后,可以使用protoc编译器将.proto编译成对应的.pb.cc.pb.h文件,如此就可以在#include "hello.pb.h"引入之后可以自动提示。 protoc编译器使用的一般格式如下, >protoc -I=\(SRC_DIR --cpp_out=\)DST_DIR $SRC_DIR/hello.proto

    e.g.

    $ protoc -I=proto --cpp_out=./ proto/hello.proto

  2. writepb.cpp 这里,protobuf类似于json主要用于数据的结构化编码,这里将Hello Protocol Buffer进行编码后,存入本地文件./hello.pb。另外有几点需要注意:

    • GOOGLE_PROTOBUF_VERIFY_VERSION宏。它是一种好的实践——虽然不是严格必须的——在使用C++ Protocol Buffer库之前执行该宏。它可以保证避免不小心链接到一个与编译的头文件版本不兼容的库版本。如果被检查出来版本不匹配,程序将会终止。注意,每个.pb.cc文件在初始化时会自动调用这个宏。
    • 在程序最后调用ShutdownProtobufLibrary()。它用于释放Protocol Buffer库申请的所有全局对象。对大部分程序,这不是必须的,因为虽然程序只是简单退出,但是 OS会处理释放程序的所有内存。然而,如果你使用了内存泄漏检测工具,工具要求全部对象都要释放,或者你正在写一个Protocol Buffer库,该库可能会被一个进程多次加载和卸载,那么你可能需要强制Protocol Buffer清除所有东西。

    #include <fstream>
    #include <string>
    #include "hello.pb.h"
    using namespace std;

    int main(){
    GOOGLE_PROTOBUF_VERIFY_VERSION;

    helloproto::helloworld hello;
    hello.set_value("Hello Protocol Buffer");
    fstream output("./hello.pb", ios::out | ios::trunc | ios::binary);
    hello.SerializeToOstream(&output);

    google::protobuf::ShutdownProtobufLibrary();

    return 0;
    }

  3. readpb.cpp 接着,再编写一个readpb程序,负责将本地文件./hello.pb中的编码数据读取,并解析、打印出来。

    #include <iostream>
    #include <fstream>
    #include <string>
    #include "hello.pb.h"
    using namespace std;

    int main(void){
    GOOGLE_PROTOBUF_VERIFY_VERSION;

    helloproto::helloworld hello;
    hello.set_value("Hello Protocol Buffer");
    fstream input("./hello.pb", ios::in | ios::binary);
    hello.ParseFromIstream(&input);

    cout << hello.value() <<endl;

    google::protobuf::ShutdownProtobufLibrary();

    return 0;
    }

  4. CMakeLists.txt 最后,将实现文件与protobuf进行链接、编译。

    .
    └── helloproto
    ├── CMakeLists.txt
    ├── proto
    │   └── hello.proto
    ├── readpb.cpp
    └── writepb.cpp

    关于CMake以及FindProtobuf更多的内容,可以参考《自动化Makefile工具——CMake项目构建》《CMake FindProtobuf》两篇文章。

    cmake_minimum_required (VERSION 2.8)
    project(helloproto)

    find_package(Protobuf REQUIRED)

    include_directories(${PROTOBUF_INCLUDE_DIRS})
    include_directories(${CMAKE_CURRENT_BINARY_DIR})
    protobuf_generate_cpp(PROTO_SRCS PROTO_HDRS proto/hello.proto)

    add_executable(readpb readpb.cpp ${PROTO_SRCS} ${PROTO_HDRS})
    add_executable(writepb writepb.cpp ${PROTO_SRCS} ${PROTO_HDRS})

    target_link_libraries(readpb ${PROTOBUF_LIBRARIES})
    target_link_libraries(writepb ${PROTOBUF_LIBRARIES}

编译、运行

亮闪闪的Hello Protocol Buffer就被打印出来了...

$ cd helloproto
$ cmake .
$ make
$ ls
CMakeLists.txt hello.pb hello.pb.cc hello.pb.h Makefile proto readpb readpb.cpp writepb writepb.cpp
$ ./writepb
$ ./readpb
Hello Protocol Buffer

References: [1] https://github.com/protocolbuffers/protobuf/blob/master/src/README.md [2] https://developers.google.com/protocol-buffers/docs/cpptutorial [3] https://cmake.org/cmake/help/git-master/module/FindProtobuf.html [4] https://github.com/protocolbuffers/protobuf [5] https://linux.cn/article-7931-1.html [6] https://zh.wikipedia.org/wiki/Protocol_Buffers