类 DRb::DRbServer

代表一个 drb 服务器实例。

在任何传入的 dRuby 调用被接受之前,或者任何本地对象被作为 dRuby 引用传递给远程进程之前,即使这些本地对象从未被远程调用,也必须在本地进程中运行 DRbServer。如果您只进行传出的 dRuby 调用并传递序列化参数,则无需在本地进程中启动 DRbServer。

除非使用多个服务器,否则本地 DRbServer 通常通过调用 DRb.start_service 启动。

常量

INSECURE_METHOD

不安全方法列表。

这些方法无法通过 dRuby 调用。

属性

config[R]

此 DRbServer 的配置

front[R]

DRbServer 的前端对象。

此对象接收对服务器的 URI 以及对象 ID 进行的远程方法调用。

thread[R]

此 DRbServer 的主线程。

这是监听并接受来自客户端的连接的线程,而不是处理每个客户端的请求-响应会话的线程。

uri[R]

此 DRbServer 的 URI

公共类方法

default_acl(acl) 点击切换源代码

将默认访问控制列表设置为 acl。默认的 ACLnil

另请参见 DRb::ACL 和 new()

# File lib/drb/drb.rb, line 1375
def self.default_acl(acl)
  @@acl = acl
end
default_argc_limit(argc) 点击切换源代码

设置 :argc_limit 选项的默认值。

参见 new()。初始默认值为 256。

# File lib/drb/drb.rb, line 1361
def self.default_argc_limit(argc)
  @@argc_limit = argc
end
default_id_conv(idconv) 点击切换源代码

Set :id_conv 选项的默认值。

参见 new()。初始默认值为 DRbIdConv 实例。

# File lib/drb/drb.rb, line 1382
def self.default_id_conv(idconv)
  @@idconv = idconv
end
default_load_limit(sz) 点击切换源代码

Set :load_limit 选项的默认值。

参见 new()。初始默认值为 25 MB。

# File lib/drb/drb.rb, line 1368
def self.default_load_limit(sz)
  @@load_limit = sz
end
new(uri=nil, front=nil, config_or_acl=nil) 点击切换源代码

创建一个新的 DRbServer 实例。

uri 是要绑定的 URI。通常格式为 ‘druby://<hostname>:<port>’,其中 <hostname> 是本地机器的主机名。如果为 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 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() 点击切换源代码

获取 :verbose 选项的默认值。

# File lib/drb/drb.rb, line 1394
def self.verbose
  @@verbose
end
verbose=(on) 点击切换源代码

Set :verbose 选项的默认值。

参见 new()。初始默认值为 false。

# File lib/drb/drb.rb, line 1389
def self.verbose=(on)
  @@verbose = on
end

公共实例方法

alive?() 点击切换源代码

此服务器是否处于活动状态?

# File lib/drb/drb.rb, line 1506
def alive?
  @thread.alive?
end
check_insecure_method(obj, msg_id) 点击切换源代码

检查方法是否可以通过 dRuby 调用。

obj 是我们要在其上调用方法的对象。msg_id 是方法名称,以 Symbol 形式表示。

如果方法是不安全的(参见 insecure_method?),则会抛出 SecurityError。如果方法是私有的或未定义的,则会抛出 NameError

# File 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
here?(uri) 点击切换源代码

uri 是否是此服务器的 URI

# File lib/drb/drb.rb, line 1511
def here?(uri)
  @exported_uri.include?(uri)
end
stop_service() 点击切换源代码

停止此服务器。

# File 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
to_id(obj) 点击切换源代码

将本地对象转换为 dRuby 引用。

# File lib/drb/drb.rb, line 1533
def to_id(obj)
  return nil if obj.__id__ == front.__id__
  @idconv.to_id(obj)
end
to_obj(ref) 点击切换源代码

将 dRuby 引用转换为它所引用的本地对象。

# File 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
verbose() 点击切换源代码

获取服务器是否处于详细模式。

在详细模式下,失败的调用将记录到标准输出。

# File lib/drb/drb.rb, line 1503
def verbose; @config[:verbose]; end
verbose=(v) 点击切换源代码

Set 是否以详细模式运行。

在详细模式下,失败的调用将记录到标准输出。

# File lib/drb/drb.rb, line 1498
def verbose=(v); @config[:verbose]=v; end

私有实例方法

any_to_s(obj) 点击切换源代码

将对象强制转换为字符串,如果对象未定义 to_s,则提供我们自己的表示。

# File lib/drb/drb.rb, line 1580
def any_to_s(obj)
  "#{obj}:#{obj.class}"
rescue
  Kernel.instance_method(:to_s).bind_call(obj)
end
error_print(exception) 点击切换源代码
# File 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
insecure_method?(msg_id) 点击切换源代码

方法是否已包含在不安全方法列表中?

# File lib/drb/drb.rb, line 1574
def insecure_method?(msg_id)
  INSECURE_METHOD.include?(msg_id)
end
main_loop() 点击切换源代码

DRbServer 内部线程执行的主循环。

接受来自客户端的连接,并启动自己的线程来处理它。此线程循环,接收来自客户端的请求,在本地对象上调用它们,并返回响应,直到客户端关闭连接或本地方法调用失败。

# File 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
run() 点击切换源代码

在新的线程中启动 DRb 主循环。

# File lib/drb/drb.rb, line 1555
def run
  Thread.start do
    begin
      while main_loop
      end
    ensure
      @protocol.close if @protocol
    end
  end
end
shutdown() 点击切换源代码
# File 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