« [番外]単純な送信時のメッセージパッシングの雰囲気 | メイン | 2章.Hello, dRuby (その6) »

2章.Hello, dRuby (その5)

本の続きに戻ります。「2.1.4 dRubyのURI」からです。小見出しの通り、DRbServerとURIとの関係についてのお話です。

TCPを使って接続する場合のdRubyのURIの書式は次の通りです。

druby://ホスト名:ポート番号

URIはホスト名とポート番号から構成されます。 URIによってdRubyのサーバを特定することができます。

URIを使用するのは、サービスの起動時とDRbObjectの生成の場面です。 DRb.start_serviceはURIとそれに関連付けるオブジェクトを指定して dRubyのサービス(DRbServer)を開始します。 DRbServerにはサーバソケットの管理やソケットを待ち受けるスレッドなどサーバプログラミングに必要なもの一式が入っています。具体的には、URIのホスト名とポート番号を用いて生成したTCPServerや、 acceptで接続を待ち受けるスレッドなどのオブジェクトです。 URIはDRbServerを特定する情報で、DRbServerは一つの固有なURIを持ちます。

DRb.start_service(uri, front)

2.1.4 dRubyのURI

ふむふむです。今までのエントリで、さらっと中身を覗いたこともあり、大体感じはわかった。ちなみに、本文中のacceptとは、クライアントからの接続があるまで待ち続けるシステムコール(もしくはシステムコールを呼び出すことのできる何か)のことだと思います。ソケット通信とかのサーバーのプログラムを自分で書くときは、大抵の場合、acceptで待ち続け、クライアントからの要求に応じてスレッドを生成したり、forkして子プロセスを作ったりすることが多いと思います(forkとは分身の術のようなものです。)。こうすることでクライアントからの複数の要求を並列に処理することが出来ます。dRubyのDRbServerのmain_loopでも、スレッドを生成して並列に処理しているのだと思います(と想像)。で次と。

URIと関連付けられたオブジェクトは、そのサービスの入り口(受け付け担当)となるため、フロントオブジェクトと呼びます。 DRbObject.new_with_uri()で作成したオブジェクトへのメソッド呼び出しは、全てこのフロントオブジェクトに届くことになります。実際のアプリケーションでは、アプリケーション内部のオブジェクトをそのまま URIに関連付けずに、アクセス制御をしたり、複数の処理をまとめて行うユーティリティ的なメソッドを用意したりした、特別なクラスをフロントに置くことが多いです。

2.1.4 dRubyのURI

DRbServerで公開するリモートオブジェクトは、フロントオブジェクトと言うのですね。で、門番とか総合受付みたいなことをさせることが多いと。図がわかりやすいです。オブジェクトを公開しているDRbServerはURIによって特定されると言うことなので、URIの理解が大事なようです。本ではしばらくURIの話が続きます。URIは下記のように一部省略できるようです。

'druby://hostname:12345' - 全て指定した完全な形
'druby://:12345' - ホスト名を省略した形式
'druby://hostname:0' - ホスト名を指定するがポート番号を省略した形式
'druby://:0' - ホスト名もポート番号も省略した形式
nil - ホスト名もポート番号も省略

2.1.4 dRubyのURI

続いて、本に従いirbで実行っと。。ちゃんとできました!!別のコンピュータとも問題なくやり取り出来ますね、dRubyのオブジェクトのやり取りは、標準でTCPSocketを使っているため、同じコンピュータのプロセス間のみではなく、別コンピュータのプロセスともやり取りできます。可能性無限大。

。。。でも、あれれ?先日のエントリで確認した限りでは、「druby://」のプロトコルでは、ポート番号の後に引数を追加して何か出来るような気がしました。

druby://ホスト名:ポート番号?オプション

URIのパース部分の正規表現はこう


/^druby:\/\/(.*?):(\d+)(\?(.*))?$/

オプションは確かDRbURIOptionになっていたやつでした。これは何に使うんだろうなあ、という疑問がわきます。メッセージ送信部分のソース(DRbMessageのsend_request)を一応みてみると

def send_request(stream, ref, msg_id, arg, b) # :nodoc:
  ary = []
  ary.push(dump(ref.__drbref))
  ary.push(dump(msg_id.id2name))
  ary.push(dump(arg.length))
  arg.each do |e|
    ary.push(dump(e))
  end
  ary.push(dump(b))
  stream.write(ary.join(''))
rescue
  raise(DRbConnError, $!.message, $!.backtrace)
end

とあります。ここのref.__drbrefは、オプション引数DRbURIOptionそのものなので、dumpされた情報には確かに含まれているようです。おそらくサーバー側でのマーシャルデータ復元時に、DRbObjectのrecv_requestとかそのあたりでよきに計らってくれるようですが、ちゃんと追いかけることができていません。このあたりの世界は、もうちょっと本を読み進めてから再挑戦することにします。

でも、内部の仕組みはともかく、オプションの利用方法くらいは知りたいなあ。と思って調べたら、咳さんのはてなに載ってました。

URIから参照を作ろうとすると、サービスの入り口のオブジェクトしか参照できないことになるんだけど、数年前に追加されたオプションを使うともうちょっと先のオブジェクトを参照できる。

druby://localhost:12345?option

「?」の後の文字列はURIのオプション引数(?)となり、frontオブジェクトにこの文字列を問い合わせた結果のオブジェクトを参照する。問い合わせはメソッドに?以後の文字列を与えて行う。

I like Ruby too. - dRubyのURIのオプション

ふむふむ、そういうことか。(てか、最近のエントリでこのサイトも紹介してくれてる!)

雰囲気を味わうために、puts00.rbをちょっと改造してみます。

require 'drb/drb'

class Puts
 def initialize(stream=$stdout)
  @stream = stream
 end
 def puts(str)
  @stream.puts("#{str} [Puts]")
 end
end

class Puts2
 def initialize(stream=$stdout)
  @stream = stream
 end
 def puts(str)
  @stream.puts("#{str} [Puts2]")
 end
end

class Front
 def initialize
  @hash = {"puts" => Puts.new, "puts2" => Puts2.new }
 end
 def [](arg)
  @hash[arg]
 end
end

uri = ARGV.shift
DRb.start_service(uri, Front.new)
puts DRb.uri
sleep

Puts2という、Putsのようなものをもうひとつ定義し、それぞれのインスタンスをハッシュに入れて切り替えられるようにしただけです。
ちなみに{}で定義できるものをハッシュといい、キーと値のペアで情報を出し入れできる便利ないれものです。なお#{hoge}は式展開といい、文字列中にオブジェクトの内容を入れることができる書き方です。Ruby好きな人は式展開が好きらしいです。

はい、で、ハッシュのキーをオプションの文字列にしました。で、クライアント側のコードは

require 'drb/drb'

there = DRbObject.new_with_uri('druby://localhost:12345?puts')
there.puts('Hello, World.')

there2 = DRbObject.new_with_uri('druby://localhost:12345?puts2')
there2.puts('Hello, World.')

とかで。するとこんな風に出ます。一応出来たのは出来た。

Hello, World. [Puts]
Hello, World. [Puts2]


今回はこれにて終了。次はリマインダーのサンプルを見ていきます。

トラックバック

このエントリーのトラックバックURL:
http://www.grandnature.net/bin/mt-tb.cgi/59

コメントを投稿

About

2007年09月14日 10:14に投稿されたエントリーのページです。

ひとつ前の投稿は「[番外]単純な送信時のメッセージパッシングの雰囲気」です。

次の投稿は「2章.Hello, dRuby (その6)」です。

他にも多くのエントリーがあります。メインページアーカイブページも見てください。