Apache Thrift を使う 3 - VCでサンプルを動かす

Posted Sun Jun 24 2012

今回は簡単なサンプルを作成してみましょう.Thrift の特徴として他言語間での RPC が可能という特徴がありますが,今回は四則演算を行う簡単なソフトをクライアント/サーバーともに C++で作成します.以下の手順で行います.

  1. thrift ファイルの定義とクライアント/サーバーコードの生成
  2. サーバーの実装
  3. クライアントの実装

1. thrift ファイルの定義とクライント/サーバーコードの生成

IDL で thrift ファイルを記述し,前回作成したコンパイラでコンパイルすることでクライアント/サーバーの通信部分を自動生成してくれます.まずは Calculator.thrift というファイルを作成し下記のように記述して下さい.

namespace cpp calc

service Calculator {
  double plus(1: double arg1, 2: double arg2),
  double minus(1: double arg1, 2: double arg2),
  double multiplies(1: double arg1, 2: double arg2),
  double divides(1: double arg1, 2: double arg2),
}

コマンドラインから

$ thrift.exe -gen cpp Calculator.thrift

gen-cpp フォルダが作成されます.詳しい定義方法については公式のドキュメントを参考にしてください.

2. サーバーの実装

gen-cpp/Calculator_server.skelton.cpp にサーバーのスケルトンが自動生成されているのでコピーし下記のようにサービス部分を実装します.libthrift.lib のリンクをお忘れなく.

#define HAVE_CONFIG_H

#include "gen-cpp/Calculator.h"
#include <thrift/protocol/TBinaryProtocol.h>
#include <thrift/server/TSimpleServer.h>
#include <thrift/transport/TServerSocket.h>
#include <thrift/transport/TBufferTransports.h>

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

using boost::shared_ptr;

using namespace ::calc;

class CalculatorHandler : virtual public CalculatorIf {
public:
  CalculatorHandler() {
    // Your initialization goes here
  }

  double plus(const double arg1, const double arg2) {
    // Your implementation goes here
    printf("plusn");
    return arg1 + arg2;
  }

  double minus(const double arg1, const double arg2) {
    // Your implementation goes here
    printf("minusn");
    return arg1 - arg2;
  }

  double multiplies(const double arg1, const double arg2) {
    // Your implementation goes here
    printf("multipliesn");
    return arg1 * arg2;
  }

  double divides(const double arg1, const double arg2) {
    // Your implementation goes here
    printf("dividesn");
    return arg1 / arg2;
  }

};

int main(int argc, char **argv) {

  WSADATA wsaData;
  WSAStartup(MAKEWORD(2, 0), &wsaData);

  int port = 9090;
  shared_ptr handler(new CalculatorHandler());
  shared_ptr processor(new CalculatorProcessor(handler));
  shared_ptr serverTransport(new TServerSocket(port));
  shared_ptr transportFactory(new TBufferedTransportFactory());
  shared_ptr protocolFactory(new TBinaryProtocolFactory());

  TSimpleServer server(processor, serverTransport, transportFactory, protocolFactory);
  server.serve();
  return 0;
}

注意点は Windows の場合,下記2行を書かないと以下のランタイムエラーが発生します.

WSADATA wsaData;
WSAStartup(MAKEWORD(2, 0), &wsaData);
TServerSocket::listen() socketpair() errno = 10093
getaddrinfo 10093: アプリケーションが WSAStartup を呼び出していない
か、または WSAStartup が失敗しました。

3. クライアントの実装

最後にクライアントを実装します.

#define HAVE_CONFIG_H

#include "gen-cpp/Calculator.h"

#include <protocol/TBinaryProtocol.h>
#include <transport/TSocket.h>
#include <transport/TTransportUtils.h>

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

using namespace calc;

int main(int argc, char** argv) {

  boost::shared_ptr socket(new TSocket("localhost", 9090));
  boost::shared_ptr transport(new TBufferedTransport(socket));
  boost::shared_ptr protocol(new TBinaryProtocol(transport));

  CalculatorClient client(protocol);

  try {
    transport->open();

    printf("2 + 3 = %fn", client.plus(2, 3));
    printf("6 - 3 = %fn", client.minus(6, 3));
    printf("8 * 3 = %fn", client.multiplies(8, 3));
    printf("16 / 5 = %fn", client.divides(16, 5));

    transport->close();
  } catch (TException& tx) {
    printf("ERROR: %sn", tx.what());
  }
  return 0;
}

まずサーバーを起動しておいて,クライアントを実行した時に計算結果が表示されれば OK です.おつかれさまでした.