Spec-Zone.ru › Ruby 2.3

класс Rinda::RingServer

Родитель:
Объект
Включенные модули:
DRb::DRbUndumped

Класс RingServer позволяет определять местоположение Rinda::TupleSpace с помощью UDP-рассылок. По умолчанию для определения сервиса используются следующие шаги:

  1. Сервер RingServer начинает прослушивать сеть по UDP-адресу широковещательной рассылки.

  2. Объект RingFinger отправляет UDP-пакет, содержащий DRb URI, по которому он будет ожидать ответа.

  3. Сервер RingServer получает UDP-пакет и подключается по DRb сервису к предоставленному DRb URI.

Для работы с RingServer требуется TupleSpace:

ts = Rinda::TupleSpace.new
rs = Rinda::RingServer.new

Сервер RingServer также может прослушивать адреса многоадресной рассылки для объявлений. Это позволяет запускать несколько RingServer на одном хосте. Для использования широковещательной рассылки и многоадресной рассылки по сети:

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) Показать исходный код
# File lib/rinda/ring.rb, line 95
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

Объявляет 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']])

Вы можете задать адреса как массив Объект. Первый элемент массива — это адрес многоадресной рассылки, а второй — адрес входного интерфейса. Если второй опущен, используется '0.0.0.0'.

Если используется IPv6-многоадресная рассылка, вам может потребоваться установить как адрес локального интерфейса, так и индекс входного интерфейса:

rs = Rinda::RingServer.new(ts, [['ff02::1', '::1', 1]])

Первый элемент — адрес многоадресной рассылки, второй — адрес входного интерфейса, третий — индекс входного интерфейса.

В настоящее время нет простого способа получить индекс интерфейса по имени.

Если второй опущен, используется '::1'. Если третий опущен, используется 0 (по умолчанию).

Публичные Методы Экземпляров

do_reply() Показать исходный код
# File lib/rinda/ring.rb, line 215
def do_reply
  tuple = @ts.take([:lookup_ring, nil], @renewer)
  Thread.new { tuple[1].call(@ts) rescue nil}
rescue
end

Извлекает кортежи поиска из TupleSpace и отправляет их DRb объекту адрес локального TupleSpace.

do_write(msg) Показать исходный код
# File lib/rinda/ring.rb, line 190
def do_write(msg)
  Thread.new do
    begin
      tuple, sec = Marshal.load(msg)
      @ts.write(tuple, sec)
    rescue
    end
  end
end

Извлекает ответ URI из msg и добавляет его в TupleSpace, где он будет получен reply_service для уведомления.

make_socket(address, interface_address=nil, multicast_interface=0) Показать исходный код
# File lib/rinda/ring.rb, line 133
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

Создает сокет по адресу address.

Если address — адрес многоадресной рассылки, то interface_address и multicast_interface могут быть заданы как необязательные.

Созданный сокет привязывается к interface_address. Если используется IPv4-многоадресная рассылка, то интерфейс interface_address используется как входной интерфейс. Если interface_address опущено или равно nil, то используется '0.0.0.0' или '::1'.

Если используется IPv6-многоадресная рассылка, то multicast_interface используется как входной интерфейс. multicast_interface — индекс сетевого интерфейса. Если multicast_interface опущено, используется 0 (по умолчанию).

reply_service() Показать исходный код
# File lib/rinda/ring.rb, line 203
def reply_service
  Thread.new do
    loop do
      do_reply
    end
  end
end

Создает поток, который уведомляет ожидающих клиентов из TupleSpace.

shutdown() Показать исходный код
# File lib/rinda/ring.rb, line 224
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

Выключает RingServer

write_services() Показать исходный код
# File lib/rinda/ring.rb, line 175
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

Создает потоки, которые собирают UDP-пакеты и передают их методу #do_write для декодирования.

Ruby Core © 1993–2017 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API