Rinda::RingServer
class Rinda::RingServer
父类:ObjectIncluded模块:DRb :: DRbUndumped
RingServer允许通过UDP广播定位Rinda :: TupleSpace。默认服务位置使用以下步骤:
- RingServer开始监听网络广播UDP地址。
- RingFinger发送一个包含DRb URI的UDP数据包,在那里它将监听回复。
- RingServer接收UDP数据包并通过DRb服务连接回提供的DRb URI。
RingServer需要TupleSpace:
ts = Rinda::TupleSpace.new
rs = Rinda::RingServer.new
RingServer也可以监听多播地址中的公告。这允许多个RingServers在同一台主机上运行。要使用网络广播和多播:
ts = Rinda::TupleSpace.new
rs = Rinda::RingServer.new ts, %w[Socket::INADDR_ANY, 239.0.0.1 ff02::1]
公共类方法
new(ts, addresses=Socket::INADDR_ANY, port=Ring_PORT) 显示源
广告ts
在给定addresses
的port
。
如果addresses
省略,则只使用UDP广播地址。
addresses
可以包含多个地址。如果给出多播地址,addresses
则RingServer将侦听多播查询。
如果使用IPv4组播,则可能需要设置加入组播组的入站接口的地址。
ts = Rinda::TupleSpace.new
rs = Rinda::RingServer.new(ts, [['239.0.0.1', '9.5.1.1']])
您可以将地址设置为数组对象。Array的第一个元素是多播地址,第二个元素是入站接口地址。如果第二个被省略,则使用“0.0.0.0”。
如果使用IPv6多播,则可能需要同时设置本地接口地址和入站接口索引:
rs = Rinda::RingServer.new(ts, [['ff02::1', '::1', 1]])
第一个元素是多播地址,第二个元素是入站接口地址。第三个是入站接口索引。
目前没有简单的方法来按名称获取接口索引。
如果第二个被省略,则使用':: 1'。如果第三个被省略,则使用0(默认接口)。
# File lib/rinda/ring.rb, line 94
def initialize(ts, addresses=[Socket::INADDR_ANY], port=Ring_PORT)
@port = port
if Integer === addresses then
addresses, @port = [Socket::INADDR_ANY], addresses
end
@renewer = Renewer.new
@ts = ts
@sockets = []
addresses.each do |address|
if Array === address
make_socket(*address)
else
make_socket(address)
end
end
@w_services = write_services
@r_service = reply_service
end
公共实例方法
do_reply() 显示源
将查找元组从TupleSpace中拉出,并将它们的DRb对象发送到本地TupleSpace的地址。
# File lib/rinda/ring.rb, line 214
def do_reply
tuple = @ts.take([:lookup_ring, nil], @renewer)
Thread.new { tuple[1].call(@ts) rescue nil}
rescue
end
do_write(msg) 显示源
从响应URI中提取响应URI msg
并将其添加到TupleSpace中,reply_service
以便通知它。
# File lib/rinda/ring.rb, line 189
def do_write(msg)
Thread.new do
begin
tuple, sec = Marshal.load(msg)
@ts.write(tuple, sec)
rescue
end
end
end
make_socket(address, interface_address=nil, multicast_interface=0)显示源
创建一个套接字 address
如果address
是多播地址,则interface_address
和multicast_interface
可设置为可选。
创建的套接字绑定interface_address
。如果您使用IPv4多播,则接口将interface_address
用作入站接口。如果interface_address
省略或零,则使用“0.0.0.0”或“:: 1”。
如果您使用IPv6多播,则将multicast_interface
其用作入站接口。multicast_interface
是网络接口索引。如果multicast_interface
省略,则使用0(默认接口)。
# File lib/rinda/ring.rb, line 132
def make_socket(address, interface_address=nil, multicast_interface=0)
addrinfo = Addrinfo.udp(address, @port)
socket = Socket.new(addrinfo.pfamily, addrinfo.socktype,
addrinfo.protocol)
@sockets << socket
if addrinfo.ipv4_multicast? or addrinfo.ipv6_multicast? then
if Socket.const_defined?(:SO_REUSEPORT) then
socket.setsockopt(:SOCKET, :SO_REUSEPORT, true)
else
socket.setsockopt(:SOCKET, :SO_REUSEADDR, true)
end
if addrinfo.ipv4_multicast? then
interface_address = '0.0.0.0' if interface_address.nil?
socket.bind(Addrinfo.udp(interface_address, @port))
mreq = IPAddr.new(addrinfo.ip_address).hton +
IPAddr.new(interface_address).hton
socket.setsockopt(:IPPROTO_IP, :IP_ADD_MEMBERSHIP, mreq)
else
interface_address = '::1' if interface_address.nil?
socket.bind(Addrinfo.udp(interface_address, @port))
mreq = IPAddr.new(addrinfo.ip_address).hton +
[multicast_interface].pack('I')
socket.setsockopt(:IPPROTO_IPV6, :IPV6_JOIN_GROUP, mreq)
end
else
socket.bind(addrinfo)
end
socket
end
reply_service()显示源
创建一个从TupleSpace通知等待客户端的线程。
# File lib/rinda/ring.rb, line 202
def reply_service
Thread.new do
loop do
do_reply
end
end
end
shutdown() 显示源
关闭RingServer
# File lib/rinda/ring.rb, line 223
def shutdown
@renewer.renew = false
@w_services.each do |thread|
thread.kill
thread.join
end
@sockets.each do |socket|
socket.close
end
@r_service.kill
@r_service.join
end
write_services() 显示源
创建拾取UDP数据包的线程并将它们传递给#do_write进行解码。
# File lib/rinda/ring.rb, line 174
def write_services
@sockets.map do |s|
Thread.new(s) do |socket|
loop do
msg = socket.recv(1024)
do_write(msg)
end
end
end
end