Thriftでバイナリデータを扱う

Thriftでバイナリデータをやりとりする方法。

以前、FlexでXML-RPCを利用していた時は、確かbase64にエンコードして返していたと思うので、
Thriftでも同様にバイナリデータはbase64にエンコードして返すようにします。
Thriftのソースを漁っていると TBase64Utils とかいうのを見つけたのですが、
どうせboost必須なフレームワークなのでboostを使ってエンコードしてみます。

インタフェースとして、
・サービス名を Test
・プロシージャ名を returnImage
・引数は画像ファイル名、戻り値はbase64エンコード文字列
を定義します。

#!/usr/bin/thrift

service Test {
  string returnImage(1: string name)
}

画像ファイルを読み込んで、base64にエンコードするだけの処理です。
boostでbase64にエンコードする方法は以下のサイトを参考にさせていただきました。
B Lifeで行こう: boostでbase64のエンコード

ここではハンドラの部分のみ、自動生成部分は省略します。

class TestHandler : virtual public TestIf {

 public:
  TestHandler() {
  }

  void returnImage(std::string& _return, const std::string& name) {
    std::ifstream ifs;
    std::ostringstream oss;
    std::string str;

    ifs.open(name.c_str(), std::ios::in | std::ios::binary);
    if(!ifs.is_open()) {
      _return = "";
    }else {
      oss<<ifs.rdbuf();
      str = oss.str();
      _return = encode_base64(str);
    }
  }

  std::string encode_base64(const std::string& src_data) {
    using namespace boost::archive::iterators;
    const int Base64_Column_Width = 76;
    typedef insert_linebreaks<base64_from_binary<transform_width<
      const char *, 6, 8> >, Base64_Column_Width> base64_encoder;

    // エンコードしたデータを格納
    std::stringstream ost_base64;
    // エンコード処理
    std::copy(
      base64_encoder(src_data.c_str()),
      base64_encoder(src_data.c_str() + src_data.length()),
      std::ostream_iterator<char>(ost_base64)
    );
    std::string base64 = ost_base64.str();
    // 末尾の長さ調整
    while(((base64.length() % (Base64_Column_Width + 1)) % 4) > 0) {
      base64 += "=";
    }
    return base64;
  }
};

次にクライアントを今回はPHPで書きます。
RPCで受け取ったbase64エンコード文字列をimgタグに埋め込んで画面に表示します。

<?php
$GLOBALS['THRIFT_ROOT'] = 'src';
$GEN_DIR = 'gen-php';

/** Include the Thrift base */
require_once $GLOBALS['THRIFT_ROOT'].'/Thrift.php';

/** Include the binary protocol */
require_once $GLOBALS['THRIFT_ROOT'].'/protocol/TBinaryProtocol.php';

/** Include the socket layer */
require_once $GLOBALS['THRIFT_ROOT'].'/transport/TSocketPool.php';

/** Include the socket layer */
require_once $GLOBALS['THRIFT_ROOT'].'/transport/TBufferedTransport.php';

/** Include the generated code */
require_once $GEN_DIR.'/test/Test.php';
require_once $GEN_DIR.'/test/test_types.php';

$transport = new TSocket('localhost', 9090);
$client = new TestClient(new TBinaryProtocol($transport));

try {
  $transport->open();
  $img = $client->returnImage("lenna.jpg");  /* $img に base64エンコード文字列が入る */
  $transport->close();
}catch(Exception $e) {
  echo $e->getMessage();
}
?>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="www.w3.org/1999/xhtml" lang="ja" xml:lang="ja">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta http-equiv="Content-Style-Type" content="text/css" />
<title>Embed Base64 Image Test</title>
</head>
<body>
<img src="data:image/jpg;base64,<?php echo $img ?>" />
</body>
</html>

こんな感じで一応上手く表示まで行うことができました。

サーバ側で画像処理を行った後、出力画像をクライアントに返す時などに使えます。
楽な方法なんですが、大きな画像データをやりとりするのには向いてないですね;;
もうちょっと良い方法を探してみます。

・関連記事
Thrift + OpenCV
Thrift::例外処理
Thriftインストール

 

Tags: ,

Comments

No comments so far.

  • Leave a Reply
     
    Your gravatar
    Your Name