Использование SO_REUSEADDR с EventMachine (через UDP) - PullRequest
0 голосов
/ 25 октября 2011

Я пытаюсь установить параметры сокета (в частности, SO_REUSEADDR) для соединения UDP с EventMachine .Как есть, фрагмент кода работает.Когда второй open_datagram_socket не закомментирован, произойдет сбой с этой ошибкой:

eventmachine.rb: 844: в `open_udp_socket ': нет сокета датаграммы (RuntimeError)

Из просмотра источникаПохоже, что он просто возвращает ноль в случае неудачи, что неудивительно.Кажется, что опция сокета просто не установлена ​​правильно, но я не знаком с библиотекой, ruby ​​или программированием сокетов, чтобы знать, что я делаю что-то не так.Я не могу себе представить, что библиотека просто не поддерживает что-то подобное, но, возможно, это возможно.

Как мне заставить SO_REUSEADDR работать с сокетом дейтаграммы?

require 'eventmachine'

class PassThruServer < EM::Connection
    def initialize
        set_sock_opt Socket::SOL_SOCKET, Socket::SO_REUSEADDR, true
    end
    def post_init()
        # too late?
#       set_sock_opt Socket::SOL_SOCKET, Socket::SO_REUSEADDR, true
    end
    def receive_data(data)
        puts "PT: "+ data.to_s()
        send_datagram data, "localhost", 6060
    end
end

class MessagePrinter < EM::Connection
    def receive_data(data)
        puts "MP: "+ data.to_s()
    end
end

EM.run do
    # pass through
    EM.open_datagram_socket "localhost", 5050, PassThruServer
#   EM.open_datagram_socket "localhost", 5050, PassThruServer

    # test consumer
    EM.open_datagram_socket "localhost", 6060, MessagePrinter

    # test producer
    EM.open_datagram_socket "localhost", nil do |conn|
        i = 1
        EM.add_periodic_timer(3) do
            data = "message: "+ i.to_s() +"\n"
            conn.send_datagram data, "localhost", 5050
            i += 1
        end
    end
end

Этопохоже, что TCP может всегда использовать SO_REUSEADDR.Я не вижу, где UDP даже инициализирует параметры сокета.Насколько я понимаю, они должны были быть установлены до того, как сокет был фактически открыт?

Я действительно не получаю привязки ruby's C, чтобы убедиться, что я смотрю в правильном месте.

1 Ответ

1 голос
/ 25 октября 2011

Мне удалось создать сокет с помощью приведенного ниже патча.Однако я не смог получить сокеты, чтобы каждый получил копию данных.

*** em.cpp  Tue Oct 25 10:52:22 2011
--- em_.cpp Tue Oct 25 10:51:38 2011
*************** EventMachine_t::OpenDatagramSocket
*** 1572,1577 ****
--- 1572,1578 ----
  const unsigned long EventMachine_t::OpenDatagramSocket (const char *address, int port)
  {
          unsigned long output_binding = 0;
+         int one = 1;

          int sd = socket (AF_INET, SOCK_DGRAM, 0);
          if (sd == INVALID_SOCKET)
*************** const unsigned long EventMachine_t::Open
*** 1606,1611 ****
--- 1607,1615 ----
                          goto fail;
          }

+         if (setsockopt (sd, SOL_SOCKET, SO_REUSEADDR, (char*) &one, sizeof(one)) < 0)
+                 goto fail;
+ 
          if (bind (sd, (struct sockaddr*)&sin, sizeof(sin)) != 0)
                  goto fail;

Я не думаю, что мой вариант использования был рассмотрен авторами библиотеки вообще.Другой параметр сокета, который нужно было установить, - IP_ADD_MEMBERSHIP.Я могу предположить, что это может быть легко взломано в слой C.Я был бы потерян, пытаясь выставить это рубиновому слою, все же.Я думаю, что это за пределами моей практической досягаемости.

Я подозреваю, что использование библиотеки vanilla ruby ​​более уместно.

...