3.5.6. pfi::network::rpc

3.5.6.1. 概要

C++間で簡単にRPCをするためのライブラリ。

3.5.6.2. 使い方

3.5.6.2.1. シグニチャの定義

RPC_PROCというマクロで関数を定義して、 RPC_GENというマクロでサーバとクライアントのクラスを生成する。

RPC_PROC(<func>, <signature>)

二つ整数をとって整数を返す、足し算のような関数を定義するなら、

RPC_PROC(add, int(int,int))

のようになる。

RPC_GEN(<version>, <prefix>, <func>, ...)

バージョンには適当な整数を指定する (サーバとクライアントでこの数値が一致しないとRPC呼び出しは失敗する)。 プリフィックスには、サーバとクライアントのクラス名のプリフィックスを指定する。 hoge と指定すると、hoge_server、hoge_clientがそれぞれサーバとクライアントのクラス名になる。 3引数目以降には関数のリストを指定する。

RPC_GEN(1, hoge, add, mul)

などが記述の一例である。

3.5.6.2.2. サーバのコード

hoge_serverクラスのインスタンスを生成し、 set_xxx()関数によって、実際に処理をさせる関数をセットし、 serv()関数でサーバを開始する。

int add(int x, int y){ return x+y; }

int main(){
  hoge_server serv;
  serv.set_add(&add);
  serv.serv(12345, 10); // ポート番号, スレッド数
}

3.5.6.2.3. クライアントのコード

hoge_clientクラスのインスタンスを生成し、 call_xxx()で呼び出せる。

hoge_client cli("localhost", 12345); // ホスト、ポート番号
cout<<cli.call_add(1,2)<<endl; // 3が返ってくるはず

呼び出しに失敗したりすると、call_xxx()はpfi::network::rpc::rpc_errorもしくはそれを継承した例外を投げる。

  • cannot_get_connection 接続できなかった

  • method_not_found サーバに要求したメソッドがなかった

  • version_mismatch クライアントの要求したバージョンがサーバのバージョンと異なった

3.5.6.2.4. ストリームの受け渡し

大きなファイルをメモリを使わずに転送したい場合などに、 ストリーム経由での引数の受け渡しが使える。

RPC_PROC(foo, void(pfi::data::serialization::stream))

と、引数をpfi::data::serialization::streamにすると、 クライアント側は、

fstream fs("hoge.txt", ios::in);
cli.call_foo(stream(f));

のように、iostream(istreamやostreamではだめなので注意)をstreamでくるんで送ることができる。

サーバ側は

void foo(stream s)
{
}

の s に適当なiostreamが作られて呼び出される (具体的には/tmp/以下に受信したデータを含むファイルが作られ、それがopenされ、sにbindされて呼び出される)。

void foo(stream s)
{
  istream &is=s.get();
  // isをつかうコード
}

fooの実行が終わると、テンポラリファイルは自動的に削除される。

3.5.6.3. 注意

RPCの引数、返り値はpficommonのシリアライズライブラリによって シリアライズ可能な型である必要がある。 シリアライザに関しての詳細はそちらを参照のこと。 ちなみに、C++のプリミティブな型や、 stlのiteratableなコンテナはすべてデフォルトでシリアライズ可能である。

RPCの引数はread-onlyである。 参照を渡してwrite-backなどということはできない。 そもそもシグニチャには参照を書いてはいけない。 複雑なデータを返したいときは、 シリアライズ可能な構造体を作って、それで返すようにする。