1

Ruby の上にカスタム クライアントを構築する作業を行っていますSSLSocket。データを受信するために、モジュールが提供するreadおよびread_nonblockメソッドを使用してきました。OpenSSL::Buffering

メッセージを受信したときに実行されるコールバックを (ユーザー定義ブロックを介して) 定義できるように、これまでに得たものを使用しようとしています。基本的に、これらの行だけで何かを実装する必要があるようです:

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ますか?

4

1 に答える 1

1

それを達成するための2つの方法を提案します。

1)Kernel.select orメソッドの使用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ドキュメントによると、Reactor パターンを使用したイベント駆動型 I/O です。

にはEventMachine必要なものがすべて揃っています。リアクターは C++ で実装され、スレッド モデルは Ruby GIL (Global Interpreter Lock) の外にあるため、ライブラリは非常に高速です。

私はしばらくの間プロダクションでそれを使用してきましたが、うまく機能しています!

両方のアプローチは要求どおりに機能するため、それらをベンチマークして、どちらがニーズに最も適しているかを確認することをお勧めします.

于 2013-11-12T17:07:54.213 に答える