1. 程式人生 > >Google Protobuf——實現跨平臺跨語言的序列化/反序列化

Google Protobuf——實現跨平臺跨語言的序列化/反序列化

Google Protobuf——實現跨平臺跨語言的序列化/反序列化

0 Overview

Google Protocol Buffer 是一個平臺無關、語言無關的結構化資料的序列化與反序列化工具。

1 Establish dev environment

wget http://protobuf.googlecode.com/files/protobuf-2.4.1.tar.gz
tar zxvf protobuf-2.4.1.tar.gz
cd protobuf-2.4.1
mkdir /Users/michael/Development/opt/protobuf-2.4.1
./configure --prefix=/Users/michael/Development/opt/protobuf-2.4.1
make
make check
make install

2 Protocol file

建立一個名為 lm.helloworld.proto 的檔案。

package lm;
message helloworld
{
    required int32  id = 1;     // ID
    required string str = 2;    // str
    optional int32  opt = 3;    // optional field
}

一般 Google Protobuf 的 protocol 檔名形如:

packageName.MessageName.proto

3 Generate protocol classes

此時的目錄結構:

protobuf-2.4.1
|---bin
|---include
|---lib
|---test
    |---lm.helloworld.proto

編譯生成 Google Protobuf 類檔案:

alias protoc='/Users/michael/Development/opt/protobuf-2.4.1/bin/protoc'
SRC_DIR=.
DST_DIR=.
protoc -I=$SRC_DIR --cpp_out=$DST_DIR $SRC_DIR/lm.helloworld.proto

此時的目錄結構為:

protobuf-2.4.1
|---bin
|---include
|---lib
|---test
    |---lm.helloworld.proto
    |---lm.helloworld.pb.cc
    |---lm.helloworld.pb.h

4 Application files

此處以 File Stream 為例。

4.1 Structured data -> Stream

#include "lm.helloworld.pb.h"
#include <iostream>
#include <fstream>

using namespace std;

int main(void)
{
    lm::helloworld msg1;
    msg1.set_id(101);
    msg1.set_str("hello");

    fstream output("./log", ios::out | ios::trunc | ios::binary);

    if (!msg1.SerializeToOstream(&output))
    {
        cerr << "Failed to write msg." << endl;
        return -1;
    }
    return 0;
}

跟已有的結構化資料結構(依據 Google Protobuf 的格式)建立資料,將結構化資料序列化到流中。

4.2 Stream -> Structured data

#include "lm.helloworld.pb.h"                                                                                                                                                                             
#include <iostream>
#include <fstream>

using namespace std;

void ListMsg(const lm::helloworld & msg)
{
    cout << msg.id() << endl; 
    cout << msg.str() << endl; 
} 

int main(int argc, char* argv[])
{ 
    lm::helloworld msg1;
    {   
        fstream input("./log", ios::in | ios::binary);
        if (!msg1.ParseFromIstream(&input))
        {   
            cerr << "Failed to parse address book." << endl;
            return -1; 
        }   
    }   
    ListMsg(msg1);
}

將流中的序列化資料,讀取到依據 Google Protobuf 的格式建立的物件中。

5 Compile executable files

5.1 Directories and file tree

protobuf-2.4.1
|---bin
|---include
|---lib
|---test
    |---lm.helloworld.proto
    |---lm.helloworld.pb.cc
    |---lm.helloworld.ph.h
    |---write.cpp
    |---read.cpp

5.2 Compile

g++ lm.helloworld.pb.cc write.cpp -o write.out -I ../include -L../lib -lprotobuf

Notice:

  • 編譯應用程式原始檔時,要記得同時編譯 lm.helloworld.pb.cc 原始檔;
  • 記得 Include Google Protobuf headers(-I ../include)
  • 記得 Link 路徑以及相應的 google protobuf libraries(-L../lib -lprotobuf)

6 Run

執行 write:

./write

會觀察到生成如下檔案(參見源程式):

log

執行 read:

./read

輸出結果:

$ ./read.out 
101
hello

7 Review

  1. 環境:搭建 Google Protobuf 的開發環境;
  2. 協議:根據 Google Protobuf 格式要求,建立 Protocol 檔案;
  3. 生成:利用 protoc 編譯生成所定義的 Protocol 的類原始檔與標頭檔案;
  4. 應用:編寫利用所生成的 Protocol 的類原始檔與標頭檔案;
  5. 編譯:編譯所編寫的應用的原始檔與標頭檔案,注意標頭檔案路徑、庫檔案路徑及庫;
  6. 執行。

Reference

  1. http://stackoverflow.com/questions/8875867/linking-errors-when-using-proto-tutorial
  2. http://www.ibm.com/developerworks/cn/linux/l-cn-gpb/
  3. http://code.google.com/intl/zh-CN/apis/protocolbuffers/docs/overview.html

-

Happy Coding, enjoy sharing!