2013-11-12 3 views
1

Я работаю над созданием пользовательского клиента поверх Ruby's SSLSocket. Чтобы получать данные, я использовал методы read и read_nonblock, предоставляемые модулем OpenSSL::Buffering.Есть ли способ получать уведомления о появлении новых данных в SSLSocket (Ruby)?

Теперь я пытаюсь взять то, что у меня есть, и сделать так, чтобы я мог определить обратный вызов (через определенный пользователем блок), который будет запускаться при получении сообщений. Похоже, что я в принципе нужно реализовать что-то в одиночку эти строки:

thread = Thread.new do 
    while !socket.closed? 
    while (data = socket.read_nonblock(1024) rescue nil) 
     @buffer << data 
    end 

    sleep 0.1 

    # ... parse full messages from @buffer & deliver to callbacks ... 
    end 
end 

thread.run 

У меня проблема такого подхода заключается в том, что это на самом деле не событийного, и может быть до 100ms задержки, поскольку данные фактически доступный. Конечно, я мог бы изменить время сна, но он просто чувствует себя немного взломанным.

Есть ли лучший подход, который я мог бы использовать для этого? Если нет, то что я должен решить, должен ли я решить реализовать более короткий/более быстрый цикл (например: sleep 0.01)?

+0

ОК, во-первых, если вы его отключили, почему вы остановились на неблокировании? –

+0

@MartinJames - Мое предположение заключалось в том, что если я выберу вызов сна, это закончится тем, что просто купит память в этом цикле. Возможно, у меня все еще не получается. –

+1

Вы посмотрели на метод «Kernel.select»? [Https://github.com/celluloid/nio4r] использует этот подход для чистой реализации Ruby. –

ответ

1

Предлагаю два способа добиться этого.

1) Используя Kernel.select или IO.select метод (как те же):

require 'socket' 
require 'openssl' 

s  = TCPSocket.new(host, prot) 
ssl = OpenSSL::SSL::SSLSocket.new(s) 
ssl.connect 

t = Thread.new do 
    loop do 
    sr, sw = IO.select [ssl] 
    puts sr.first.readline 
    puts '...' 
    end 
end 

puts 'start reading' 
t.join # join the main thread 

В IO.select ждет, пока некоторые данные не прибыли, без шумного цикла. Преимущество этого решения заключается в использовании стандартной библиотеки Ruby.

2) Использование EventMachine библиотеки:

require 'eventmachine' 

module Client 

    def post_init 
    start_tls 
    end 

    def receive_data data 
    # include callback code 
    puts data 
    puts '...' 
    end 

end 

EM.run do 
    # start event loop 
    EM.connect 'localhost', 9000, Client 
end 

EventMachine, в соответствии с документацией, является управляемой событиями ввода/вывода с использованием шаблона реактора.

В EventMachine есть все, что вам нужно из коробки. Реактор реализован на C++, а модель потока находится за пределами Ruby GIL (Global Interpreter Lock), что делает библиотеку очень быстрой.

Я использую его на производстве некоторое время и отлично работает!

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

+0

Спасибо за тщательный ответ и разоблачение меня несколькими методами, которые я никогда не видел/не использовал! Я знаком с EventMachine, но не знал, что могу использовать его для сокетов SSL. Я обязательно проверю это! –

 Смежные вопросы

  • Нет связанных вопросов^_^