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インストール


Comments
No comments so far.