class DRb::DRbServer
表示 drb 服务器实例的类。
在可以接受任何传入的 dRuby 调用,或将任何本地对象作为 dRuby 引用传递给远程进程之前,即使这些本地对象实际上从未被远程调用,也必须在本地进程中运行 DRbServer。 如果您只是进行传出 dRuby 调用并传递编组的参数,则无需在本地进程中启动 DRbServer。
除非使用多个服务器,否则通常通过调用DRb.start_service
来启动本地 DRbServer。
常量
- INSECURE_METHOD
不安全方法的列表。
这些方法不能通过 dRuby 调用。
属性
此 DRbServer 的配置
DRbServer 的前端对象。
此对象接收在服务器的 URI 上单独进行的远程方法调用,并带有对象 ID。
此 DRbServer 的主线程。
这是侦听并接受来自客户端的连接的线程,而不是处理每个客户端的请求-响应会话的线程。
此 DRbServer 的 URI。
公共类方法
设置 :argc_limit 选项的默认值。
请参见 new()。 初始默认值为 256。
# File drb-2.2.1/lib/drb/drb.rb, line 1361 def self.default_argc_limit(argc) @@argc_limit = argc end
设置 :id_conv 选项的默认值。
请参见 new()。 初始默认值是 DRbIdConv
实例。
# File drb-2.2.1/lib/drb/drb.rb, line 1382 def self.default_id_conv(idconv) @@idconv = idconv end
设置 :load_limit 选项的默认值。
请参见 new()。 初始默认值为 25 MB。
# File drb-2.2.1/lib/drb/drb.rb, line 1368 def self.default_load_limit(sz) @@load_limit = sz end
创建一个新的 DRbServer 实例。
uri
是要绑定的 URI。 这通常采用“druby://<主机名>:<端口>”的形式,其中 <主机名> 是本地计算机的主机名。 如果为 nil,则将在系统选择的端口上绑定到系统的默认主机名; 这些值可以从 uri
属性中检索。“druby:”指定默认的 dRuby 传输协议:可以指定其他协议,例如“drbunix:”。
front
是服务器的前端对象,即服务器上远程方法调用将传递到的对象。 如果为 nil,则服务器将不接受远程方法调用。
如果 config_or_acl
是哈希值,则是用于此服务器的配置。 识别以下选项
- :idconv
-
一个 id 到对象的转换对象。 默认为
DRb::DRbIdConv
类的实例。 - :verbose
-
如果为 true,则服务器中对象的所有不成功的远程调用都将记录到 $stdout。 默认为 false。
- :tcp_acl
-
此服务器的访问控制列表。 请参阅主要 dRuby 分发中的
ACL
类。 - :load_limit
-
服务器接受的最大消息大小(以字节为单位)。 默认为 25 MB (26214400)。
- :argc_limit
-
服务器接受的远程方法的最大参数数量。 默认为 256。
这些选项的默认值可以通过类方法 default_argc_limit、default_load_limit、default_acl、default_id_conv 和 verbose=
在类范围内进行修改
如果 config_or_acl
不是哈希值,但不是 nil,则假定它是此服务器的访问控制列表。 有关更多详细信息,请参见 :tcp_acl 选项。
如果当前没有其他服务器设置为主服务器,则这将成为主服务器。
服务器将立即在其自己的线程中开始运行。
# File drb-2.2.1/lib/drb/drb.rb, line 1451 def initialize(uri=nil, front=nil, config_or_acl=nil) if Hash === config_or_acl config = config_or_acl.dup else acl = config_or_acl || @@acl config = { :tcp_acl => acl } end @config = self.class.make_config(config) @protocol = DRbProtocol.open_server(uri, @config) @uri = @protocol.uri @exported_uri = [@uri] @front = front @idconv = @config[:idconv] @grp = ThreadGroup.new @thread = run DRb.regist_server(self) end
获取 :verbose 选项的默认值。
# File drb-2.2.1/lib/drb/drb.rb, line 1394 def self.verbose @@verbose end
设置 :verbose 选项的默认值。
请参见 new()。 初始默认值为 false。
# File drb-2.2.1/lib/drb/drb.rb, line 1389 def self.verbose=(on) @@verbose = on end
公共实例方法
此服务器是否处于活动状态?
# File drb-2.2.1/lib/drb/drb.rb, line 1506 def alive? @thread.alive? end
检查是否可以通过 dRuby 调用方法。
obj
是我们要在其上调用方法的对象。 msg_id
是方法名称,作为 Symbol。
如果该方法是不安全方法(请参见 insecure_method?
),则会引发 SecurityError。 如果该方法是私有的或未定义的,则会引发 NameError。
# File drb-2.2.1/lib/drb/drb.rb, line 1594 def check_insecure_method(obj, msg_id) return true if Proc === obj && msg_id == :__drb_yield raise(ArgumentError, "#{any_to_s(msg_id)} is not a symbol") unless Symbol == msg_id.class raise(SecurityError, "insecure method '#{msg_id}'") if insecure_method?(msg_id) case obj when Object if obj.private_methods.include?(msg_id) desc = any_to_s(obj) raise NoMethodError, "private method '#{msg_id}' called for #{desc}" elsif obj.protected_methods.include?(msg_id) desc = any_to_s(obj) raise NoMethodError, "protected method '#{msg_id}' called for #{desc}" else true end else if Kernel.instance_method(:private_methods).bind(obj).call.include?(msg_id) desc = any_to_s(obj) raise NoMethodError, "private method '#{msg_id}' called for #{desc}" elsif Kernel.instance_method(:protected_methods).bind(obj).call.include?(msg_id) desc = any_to_s(obj) raise NoMethodError, "protected method '#{msg_id}' called for #{desc}" else true end end end
uri
是此服务器的 URI 吗?
# File drb-2.2.1/lib/drb/drb.rb, line 1511 def here?(uri) @exported_uri.include?(uri) end
停止此服务器。
# File drb-2.2.1/lib/drb/drb.rb, line 1516 def stop_service DRb.remove_server(self) if Thread.current['DRb'] && Thread.current['DRb']['server'] == self Thread.current['DRb']['stop_service'] = true else shutdown end end
将本地对象转换为 dRuby 引用。
# File drb-2.2.1/lib/drb/drb.rb, line 1533 def to_id(obj) return nil if obj.__id__ == front.__id__ @idconv.to_id(obj) end
将 dRuby 引用转换为它引用的本地对象。
# File drb-2.2.1/lib/drb/drb.rb, line 1526 def to_obj(ref) return front if ref.nil? return front[ref.to_s] if DRbURIOption === ref @idconv.to_obj(ref) end
获取服务器是否处于详细模式。
在详细模式下,失败的调用将记录到 stdout。
# File drb-2.2.1/lib/drb/drb.rb, line 1503 def verbose; @config[:verbose]; end
设置是否在详细模式下运行。
在详细模式下,失败的调用将记录到 stdout。
# File drb-2.2.1/lib/drb/drb.rb, line 1498 def verbose=(v); @config[:verbose]=v; end
私有实例方法
将对象强制转换为字符串,如果未为对象定义 to_s,则提供我们自己的表示形式。
# File drb-2.2.1/lib/drb/drb.rb, line 1580 def any_to_s(obj) "#{obj}:#{obj.class}" rescue Kernel.instance_method(:to_s).bind_call(obj) end
# File drb-2.2.1/lib/drb/drb.rb, line 1696 def error_print(exception) exception.backtrace.inject(true) do |first, x| if first $stderr.puts "#{x}: #{exception} (#{exception.class})" else $stderr.puts "\tfrom #{x}" end false end end
方法是否已包含在不安全方法的列表中?
# File drb-2.2.1/lib/drb/drb.rb, line 1574 def insecure_method?(msg_id) INSECURE_METHOD.include?(msg_id) end
DRbServer 的内部线程执行的主循环。
接受来自客户端的连接,并启动自己的线程来处理它。 该线程循环,接收来自客户端的请求,在本地对象上调用它们,并返回响应,直到客户端关闭连接或本地方法调用失败。
# File drb-2.2.1/lib/drb/drb.rb, line 1714 def main_loop client0 = @protocol.accept return nil if !client0 Thread.start(client0) do |client| @grp.add Thread.current Thread.current['DRb'] = { 'client' => client , 'server' => self } DRb.mutex.synchronize do client_uri = client.uri @exported_uri << client_uri unless @exported_uri.include?(client_uri) end _last_invoke_method = nil loop do begin succ = false invoke_method = InvokeMethod.new(self, client) succ, result = invoke_method.perform error_print(result) if !succ && verbose unless DRbConnError === result && result.message == 'connection closed' client.send_reply(succ, result) end rescue Exception => e error_print(e) if verbose ensure _last_invoke_method = invoke_method client.close unless succ if Thread.current['DRb']['stop_service'] shutdown break end break unless succ end end end end
在新线程中启动 DRb
主循环。
# File drb-2.2.1/lib/drb/drb.rb, line 1555 def run Thread.start do begin while main_loop end ensure @protocol.close if @protocol end end end
# File drb-2.2.1/lib/drb/drb.rb, line 1540 def shutdown current = Thread.current if @protocol.respond_to? :shutdown @protocol.shutdown else [@thread, *@grp.list].each { |thread| thread.kill unless thread == current # xxx: Thread#kill } end @thread.join unless @thread == current end