有没有办法通知SSLSocket(Ruby)中的新数据?

时间:2013-11-12 00:16:01

标签: ruby sockets asynchronous tcpsocket

我正在建立一个基于Ruby SSLSocket的自定义客户端。为了接收数据,我一直在使用OpenSSL::Buffering模块提供的readread_nonblock方法。

我现在正试图采取我目前所做的,并使其能够定义一个回调(通过用户定义的块),该回调将在收到消息时运行。看起来我基本上需要单独实现这些内容:

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

我对这种方法的问题在于它并非真正的事件驱动,并且由于数据实际可用,因此可能会有长达100毫秒的延迟。当然,我可以改变睡眠时间,但它只是感觉有点黑客。

我可以使用更好的方法吗?如果不是,如果我决定实施更短/更快的循环(例如:sleep 0.01),我应该有什么顾虑?

1 个答案:

答案 0 :(得分:1)

我建议两种方法来实现它。

1)使用Kernel.selectIO.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是使用Reactor模式的事件驱动I / O.

EventMachine只需开箱即用。反应器是用C ++实现的,线程模型在Ruby GIL(全局解释器锁)之外,这使得库非常快。

我一直在生产中使用它并且效果很好!

这两种方法都可以按照您的要求进行操作,因此我建议对它们进行基准测试,看看哪种方法最符合您的需求。