咳です。

次期shttpsrvのモジュールにと温めていた分散(?)Rubyを
シンプルに書き直してみました。1.2系では動きません。
お目汚しにどうぞ。

method_missing のあたりがとくに自信ないです。

drb.rb --- distributed Rubyモジュール
drbs.rb --- サンプルサーバー
drbc.rb --- サンプルクライアント

分散オブジェクトって聞きかじった程度なので
どんな機能が必要でどんな用語があるかなど、
よくわかっていないのでへんな間違いがあると思います。



使い方

はじめに自局の Remote Object ハンドラを起動します。
front はクライアントが Remote Object を指定しなかったときに
返事をするオブジェクトです。

  DRb.start_server('druby://hostname:port', front)

ネーミングサービスなどは front を使って実現できそうです。

  
クライアントはデフォルトの Remote Object を作って、
普通にメッセージを送ります。

  ro = DRbObject.new(nil, 'druby://server:prot')
  ro.sample(1, DRbEx.new(2), 3)

引数のオブジェクトは Marshal::dump して送りますが、
dump不能なときは Remote Object に変換されて送ります。
dumpされたくないときは、dumpできないようにしておくか、
DRbObject.new(obj) で Remote Object に明示的に変換して逃げます。

GCされて動かなくなりそうなときは自分で保護して下さい。




drb.rb #!/usr/local/bin/ruby =begin Tiny distributed Ruby --- dRuby DRb --- dRuby module. DRbProtocol --- Mixin class. DRbObject --- dRuby remote object. DRbConn --- DRbServer --- dRuby message handler. =end require 'socket' require 'marshal' module DRb def start_service(uri, front=nil) @uri = uri.to_s @front = front @server = DRbServer.new(@uri) @thread = @server.run end module_function :start_service attr :uri module_function :uri attr :thread module_function :thread attr :front module_function :front end module DRbProtocol def parse_uri(uri) if uri =~ /^druby:\/\/(.+?):(\d+)/ host = $1 port = $2.to_i [host, port] else raise RuntimeError, 'can\'t parse uri' end end def dump(obj, soc) begin str = Marshal::dump(obj) rescue ro = DRbObject.new(obj) str = Marshal::dump(ro) end soc.write(str) if soc return str end def send_request(soc, ref,msg_id, *arg) dump(ref, soc) dump(msg_id.id2name, soc) dump(arg.length, soc) arg.each do |e| dump(e, soc) end end def recv_reply(soc) succ = Marshal::load(soc) result = Marshal::load(soc) [succ, result] end def recv_request(soc) ro = Marshal::load(soc) msg = Marshal::load(soc) argc = Marshal::load(soc) argv = [] argc.times do argv.push Marshal::load(soc) end [ro, msg, argv] end def send_reply(soc, succ, result) dump(succ, soc) dump(result, soc) end end class DRbObject def initialize(obj, uri=nil) @uri = uri || DRb.uri @ref = obj.id if obj end def method_missing(msg_id, *a) succ, result = DRbConn.new(@uri).send_message(self, msg_id, *a) raise result if ! succ result end attr :ref end class DRbConn include DRbProtocol def initialize(remote_uri) @host, @port = parse_uri(remote_uri) end def send_message(ref, msg_id, *arg) begin soc = TCPSocket.open(@host, @port) send_request(soc, ref, msg_id, *arg) recv_reply(soc) ensure soc.close if soc # ObjectSpace.garbage_collect end end end class DRbServer include DRbProtocol def initialize(uri) @host, @port = parse_uri(uri) @soc = TCPServer.open(@port) @uri = uri.dup end def run Thread.start do while true proc end end end def proc ns = @soc.accept Thread.start do begin s = ns begin ro, msg, argv = recv_request(s) if ro and ro.ref obj = ObjectSpace._id2ref(ro.ref) else obj = DRb.front end result = obj.__send__(msg.intern, *argv) succ = true rescue result = $! succ = false end send_reply(s, succ, result) ensure close s if s # ObjectSpace.garbage_collect end end end end
drbs.rb #!/usr/local/bin/ruby require 'drb.rb' class DRbEx def initialize @hello = 'hello' end def hello @hello end def sample(a, b, c) a.to_i + b.to_i + c.to_i end end if __FILE__ == $0 DRb.start_service('druby://localhost:7640', DRbEx.new) DRb.thread.join end
#!/usr/local/bin/ruby require 'drb.rb' class DRbEx2 def initialize(n) @n = n end def _dump raise TypeError, 'can\'t dump' end def to_i @n.to_i end end if __FILE__ == $0 DRb.start_service('druby://localhost:7950') ro = DRbObject.new(nil, 'druby://localhost:7640') p ro.hello p ro.sample(DRbEx2.new(1), 2, 3) p ro.sample(1, ro.sample(DRbEx2.new(1), 2, 3), DRbEx2.new(3)) end