RingServer allows a
Rinda::TupleSpace to be located via UDP broadcasts. Default service location uses the following steps:
RingServerbegins listening on the network broadcast UDP address.
RingFingersends a UDP packet containing the
URIwhere it will listen for a reply.
RingServerreceives the UDP packet and connects back to the provided
RingServer requires a TupleSpace:
ts = Rinda::TupleSpace.new rs = Rinda::RingServer.new
RingServer can also listen on multicast addresses for announcements. This allows multiple RingServers to run on the same host. To use network broadcast and multicast:
ts = Rinda::TupleSpace.new rs = Rinda::RingServer.new ts, %w[Socket::INADDR_ANY, 188.8.131.52 ff02::1]
ts on the given
addresses is omitted only the UDP broadcast address is used.
addresses can contain multiple addresses. If a multicast address is given in
addresses then the
RingServer will listen for multicast queries.
If you use IPv4 multicast you may need to set an address of the inbound interface which joins a multicast group.
ts = Rinda::TupleSpace.new rs = Rinda::RingServer.new(ts, [['184.108.40.206', '220.127.116.11']])
If you use IPv6 multicast you may need to set both the local interface address and the inbound interface index:
rs = Rinda::RingServer.new(ts, [['ff02::1', '::1', 1]])
The first element is a multicast address and the second is an inbound interface address. The third is an inbound interface index.
At this time there is no easy way to get an interface index by name.
If the second is omitted then ‘::1’ is used. If the third is omitted then 0 (default interface) is used.
# 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
Creates a socket at
address is multicast address then
multicast_interface can be set as optional.
A created socket is bound to
interface_address. If you use IPv4 multicast then the interface of
interface_address is used as the inbound interface. If
interface_address is omitted or nil then ‘0.0.0.0’ or ‘::1’ is used.
If you use IPv6 multicast then
multicast_interface is used as the inbound interface.
multicast_interface is a network interface index. If
multicast_interface is omitted then 0 (default interface) is used.
# 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) 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 rescue socket = socket.close if socket raise ensure @sockets << socket if socket end
Creates a thread that notifies waiting clients from the
# File lib/rinda/ring.rb, line 206 def reply_service Thread.new do loop do do_reply end end end
Shuts down the
# File lib/rinda/ring.rb, line 227 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
Creates threads that pick up UDP packets and passes them to
do_write for decoding.
# File lib/rinda/ring.rb, line 178 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