public
Created

1st druby. [ruby-list:15406]

  • Download Gist
drb.rb
Ruby
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164
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

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.