Ruby 2.3.0 リファレンスマニュアル > ライブラリ一覧 > drbライブラリ
分散オブジェクトプログラミングのためのライブラリです。
Ruby のプロセスから他のRubyプロセスにあるオブジェクトのメソッド を呼びだすことができます。他のマシン上のプロセスにも アクセスできます。
dRuby は Ruby 専用の分散オブジェクトシステムです。 Ruby のみで記述され、TCP socket のような Ruby 本体が提供する 通信手段があれば追加のインストール物なしに利用可能です。 独自のプロトコルで通信し、他の分散オブジェクトシステム (CORBA, RMI, .NETなど)との相互運用性はありません。
dRuby は
ができます。これらはすべて透過的に行われます。
リモートプロセスにあるオブジェクトはローカルには DRb::DRbObject の インスタンスとして表現されます。このオブジェクトはリモートオブジェクトの proxy のように振舞います。つまり、このオブジェクトのメソッドを呼び出すと リモートオブジェクトに転送されます。 CORBA の IDL のようなリモートオブジェクトのインターフェースを 静的に宣言する必要はなく、すべては実行時に解決されます。
リモートプロセスからのメソッド呼出しはそれを受け取ったプロセスの DRb::DRbServer オブジェクトが処理します。 受け取ったメッセージからメソッド呼出し情報を取り出し、ローカルにある オブジェクトを特定し、 そのメソッドを呼び出し、返り値をリモートの呼び出し元に送ります。 どのようなオブジェクトのメソッドも呼びだすことができます。 何か特別なインターフェースを実装したり、特別な mixin を必要としたりは しません。 オブジェクトの特定は DRb::DRbServer が自動でします。そのため オブジェクトの登録のようなことは通常必要ありません。
DRb::DRbServer に URI(例: druby://example.com:8787)を関連付けること で、他のプロセスからの通信(リモートメソッド呼び出し)ができるようになります (逆に言うと、URIを指定しないことで、他のプロセスからのリモートメソッド 呼び出しを拒否することができます)。 また、DRb::DRbServer に「フロントオブジェクト」を登録しておくと、 サーバの URI からそのオブジェクトをリモートオブジェクト として取り出すことができます。通常はこのオブジェクトから辿って 必要な(リモート)オブジェクトを取り出します。
リモートメソッド呼び出しはかなりの部分、同じプロセス内の オブジェクトのメソッドを呼び出すのと同じ動作をします。 ブロック付きのメソッド呼び出しもできますし、 リモートプロセス上で生じた例外はローカルプロセス上に 転送されます。DRb 関連の例外は DRb::DRbError の サブクラスです。
リモートメソッド呼び出しの引数や返り値には任意の Ruby オブジェクト が使えます。デフォルトではオブジェクトをマーシャリングして 渡され、受け取った側が元のオブジェクトに戻します。つまり オブジェクトはコピーされます。これは通常の同一プロセス上での メソッド呼び出しと大きく異なる点です(通常のメソッド呼び出しでは オブジェクトへのリファレンスが渡されます)。
ただし、マーシャリング不可能なオブジェクトは dRuby によって ある種のリファレンスとして取り扱われます。これは DRb::DRbObject のインスタンスとして表現されます。これはリモートオブジェクトの proxy として動作し、proxy のメソッドを呼び出すと上に説明した通りの 方法でリモートオブジェクトのメソッドを呼び出します。
マーシャリング可能なオブジェクトを DRbObject でリファレンスとして 渡したい、つまりコピーでなくリファレンスで渡したい場合は そのオブジェクトに DRb::DRbUndumped を Module#include します。
dRuby はブロック付きのメソッド呼び出しをサポートしていますが、 Proc はマーシャリング不可能なので、ブロックの中身は (リモート側でなく)ローカルプロセス上で実行されます。 リモート側がブロックを呼び出そうとすると、ブロックの引数が リモート側からローカル側に(上で説明したようにコピーもしくは dRuby のリファレンス オブジェクトとして)渡され、ブロックが実行され、その返り値がリモート側に 送られます。
dRuby でインターネット上に公開するサービスを作るべきではありません。 イントラネットのサービスとして動かす場合もセキュリティには気を使う 必要があるでしょう。
あるオブジェクトへの外部からのアクセスを許可すると、単にそのオブジェクトの メソッドを外部から呼び出せるだけでなく、任意の Ruby のコードを実行できて しまいます。例えば以下のようなことができます。
# !! 危険 !! ro = DRbObject.new_with_uri("druby://your.server.com:8989") class << ro # リモートオブジェクトの instance_eval を呼ぶため # ローカルオブジェクトの instance_eval を取り除く undef :instance_eval end ro.instance_eval("DANGEROUS RUBY CODE!")
このような instance_eval による危険性は $SAFE を 1 にすることで防げます。 DRb.#start_service の :safe_level オプションで リモートからのメソッド呼び出しのコンテキストで指定されるセーフレベルを 指定できます。
また、DRb::DRbServer にはアクセスコントロールリスト(アクセスを許可/拒否 する IP のリスト)によりアクセス制御をすることができます。 この機能は ACL で実現されています。 このアクセス制御は単体で使うのではなく、 適切なファイアウォールと併用すべきです。
単純なクライアント-サーバシステムの例。
ターミナルを2つサーバ側/クライアント側として起動して、サーバ側を 先に動かしてください。
require 'drb/drb' # 通信を待ち受ける URI SERVER_URI="druby://localhost:8787" class TimeServer def get_current_time return Time.now end end # サーバ側でリクエストを受け付けるオブジェクト FRONT_OBJECT=TimeServer.new # サーバを起動する DRb.start_service(SERVER_URI, FRONT_OBJECT, :safe_level => 1) # DRb のスレッドが終了するのを待つ DRb.thread.join
require 'drb/drb' # 接続先の URI SERVER_URI="druby://localhost:8787" # DRbサーバを起動する # この例には必要ないが、front オブジェクト以外の # リモートオブジェクトのメソッドを呼び出す時には必要 DRb.start_service # リモートオブジェクトの取得 timeserver = DRbObject.new_with_uri(SERVER_URI) # リモートメソッドの呼び出し puts timeserver.get_current_time
DRb::DRbIdConv | オブジェクトと識別子を相互に変換するクラスです。 |
DRb::DRbObject | リモートの dRuby オブジェクトを表すオブジェクトです。 |
DRb::DRbServer | dRuby サーバクラス。 |
DRb::DRbUnknown | リモートプロセスからマーシャリングされて送られてきたオブジェクトで、 そのクラスがローカルプロセス内では不明であるようなものを 表すクラス。 |
DRbIdConv | Alias of DRb::DRbIdConv |
DRbObject | Alias of DRb::DRbObject |
DRb | drb ライブラリの名前空間となるモジュール。 |
DRb::DRbProtocol | drb で使われる通信プロトコルを取り扱うモジュールです。 |
DRb::DRbUndumped | このモジュールをインクルードしたクラスのインスタンスは ネットワーク越しに参照渡しで渡されるようになります。 値渡し出来ないオブジェクトを drb と一緒に使う時に有用です。 |
DRbUndumped | Alias of DRb::DRbUndumped |
DRb::DRbError | drb ライブラリ固有の例外を表すクラス |
DRb::DRbBadScheme | プロトコルクラスが受け取った URI の schema が そのクラスでサポートされていないことを、伝えるための例外。 |
DRb::DRbBadURI | URI に含まれている schema をサポートしているプロトコルが見付からない ことを意味する例外クラス。 |
DRb::DRbConnError | 通信エラーが発生したことを意味する例外クラス。 |
DRb::DRbRemoteError | 例外オブジェクトを wrap したクラス |
DRb::DRbServerNotFound | カレントサーバが見付からない場合に発生する例外のクラス |
DRb::DRbUnknownError | DRb::DRbUnknown をラップする例外クラスです。 |
drb/acl | drb で用いる ACL(Access Control List)を定義するライブラリ。 |
drb/extserv | DRb::ExtServ を定義しているライブラリ。 |
drb/extservm | DRb::ExtServManager を定義しているライブラリ。 |
drb/gw | drb 通信を中継するゲートウェイ(DRb::GW)と、 中継に必要なオブジェクト識別子変換クラス(DRb::GWIdConv)、 および DRb::DRbObject への拡張が含まれています。 |
drb/observer | DRb 用の修正をした Observable (DRb::DRbObservable) を定義するライブラリ。 |
drb/ssl | DRb のプロトコルとして SSL/TLS 上で通信する drbssl が使えるようになります。 |
drb/timeridconv | DRb::DRbIdConv の拡張 DRb::TimerIdConv を定義 するライブラリ。 DRb::DRbIdConv の GC 問題をタイムアウトを定めることで 部分的に解決します。 |
drb/unix | DRb のプロトコルとして UNIX ドメインソケット経由で通信する drbunix が使えるようになります。 |