thriftによるオブジェクトのシリアル化

3961 ワード

1シーン
プロジェクト開発では、あるオブジェクトを文字列にシリアル化した後、ネットワークを介して遠くに転送したり、データベースに書き込んだりして、別のプログラムがこの文字列を取り出してオブジェクトに逆列化する必要があるというニーズがよくあります.一般的にネットワーク通信の開発にはこのようなニーズがあり、異なるオブジェクト構造に基づいてシリアル化と反シリアル化の操作を絶えず作成することは、かなり面倒ですが、thriftはスクリプト、コマンドだけで必要なコードを生成する良いスキームを提供しています.そこで、thriftを使用してオブジェクトをシリアル化する方法を例に説明します.
2考え方
thriftの4層構造では、rpcを行う必要がないため、プロセッサ層やサーバ層は必要ありません.転送層は他のマシンに転送したりデータベースに書き込む必要はありません.メモリに書くだけでいいので、TMemoryBufferを選択すると、プロトコルは比較的簡単なTbinaryProtocolを選択します.
3開発
3.1スクリプトの作成
message.thrift
//   
struct Head
{
    1:i32 id; 
    2:string from;
    3:string to; 
}

//   
struct Body
{
    1:i16 code;
    2:string msg;
}

//  
struct Message
{
    1:Head  mHead;
    2:Body  mBody;
}

主にMessageのオブジェクトがあり、メッセージヘッダとメッセージボディがあり、それぞれの属性があります.
3.2 thriftコマンドを使用してスクリプトをコード化
$>thrift -gen cpp message.thrfit

このとき、現在のディレクトリの下にgen-cppのディレクトリが生成され、4つのファイルが含まれます.
message_types.h
message_types.cpp
message_constants.h
message_constants.cpp
必要なのはmessageだけですtypes.hとmessage_types.cppなので、この2つのファイルをコピーします.
3.3呼び出し方法の作成
thrift_archive.hpp
#pragma once
#include <boost/shared_ptr.hpp>
#include <thrift/transport/TBufferTransports.h>
#include <thrift/protocol/TProtocol.h>
#include <thrift/protocol/TBinaryProtocol.h>

using namespace apache::thrift;
using namespace apache::thrift::transport;
using namespace apache::thrift::protocol;

template<typename T>
void thrift_iserialize(T& tag, std::string& s)
{
    boost::shared_ptr<TMemoryBuffer> trans(
            new TMemoryBuffer((uint8_t*)&s[0], s.size()));
    boost::shared_ptr<TProtocol> proto(new TBinaryProtocol(trans));
    tag.read(proto.get());
}

template<typename T>
void thrift_oserialize(T& tag, std::string& s)
{
    boost::shared_ptr<TMemoryBuffer> trans(new TMemoryBuffer());
    boost::shared_ptr<TProtocol> proto(new TBinaryProtocol(trans));
    tag.write(proto.get());
    s = trans->getBufferAsString();
}

感覚オブジェクトのシリアル化と逆シリアル化はよく使われるので、2つの関数テンプレート、thrift_と書きました.iserializeは文字列をオブジェクトに逆列化し、thrift_oserializeは、オブジェクトを文字列にシリアル化します.
main.cpp
#include <iostream>
#include "thrift_archive.hpp"
#include "message_types.h"


int main()
{
    Message msg;
    std::string s;

    msg.mHead.id = 1;
    msg.mHead.from = ""; 
    msg.mHead.to = ""; 

    msg.mBody.code = 100;
    msg.mBody.msg = "hello";

    thrift_oserialize(msg, s); 

    std::cout << s <<std::endl;

    Message tmp;
    thrift_iserialize(tmp, s); 
    return 0;
}

まずMessageのオブジェクトmsgをインスタンス化し、そのオブジェクトに属性値を設定し、文字列sにシリアル化し、sをtmpオブジェクトに逆直列化し、最後にmsgとtmpの属性値は一致する.
3.4 cmakeコンパイルの作成
cmakeスクリプトの作成を覚えたばかりなので、忘れないように覚えておきます.もちろんg++で直接コンパイルすることもできます
g++ -o test -DHAVE_NETINET_IN_H -I/usr/local/thrift/include -I/usr/local/boost/include -L/usr/local/thrift/lib -L/usr/local/boost/lib -lthriftnb -lthrift -levent message_types.cpp main.cpp
CMakeLists.txt
CMAKE_MINIMUM_REQUIRED(VERSION 2.8) 
PROJECT(test)
MESSAGE(STATUS "Project: ${PROJECT_NAME}") 
MESSAGE(STATUS "Project Directory: ${PROJECT_SOURCE_DIR}")

SET(CMAKE_BUILE_TYPE DEBUG) 
SET(CMAKE_CXX_FLAGS_DEBUG "-g -Wall")
ADD_DEFINITIONS("-DHAVE_NETINET_IN_H")

INCLUDE_DIRECTORIES(
${PROJECT_SOURCE_DIR}/include
/usr/local/boost/include
/usr/local/thrift/include
/usr/local/log4cxx/include
)

LINK_DIRECTORIES(
${PROJECT_SOURCE_DIR}/lib
/usr/local/boost/lib
/usr/local/thrift/lib
/usr/local/log4cxx/lib
)

SET(SOURCE_FILES 
main.cpp
message_types.cpp
)

ADD_EXECUTABLE(test ${SOURCE_FILES})
TARGET_LINK_LIBRARIES(test thrift thriftnb)

コマンドの実行:
$>cmake .
$>make

そしてgdbでデバッグすると結果が表示されます.