サーバーに接続してデータを待機するクライアント Ruby ライブラリを構築していますが、ユーザーがメソッドを呼び出してデータを送信することもできます。
私が使用するメカニズムは、次のようにソケット ペアを初期化するクラスを持つことです。
def initialize
@pipe_r, @pipe_w = Socket.pair(:UNIX, :STREAM, 0)
end
サーバーにデータを送信するために開発者が呼び出せるようにするメソッドは次のようになります。
def send(data)
@pipe_w.write(data)
@pipe_w.flush
end
socket
次に、サーバーに接続された と から選択する別のスレッドにループがあり@pipe_r
ます。
def socket_loop
Thread.new do
socket = TCPSocket.new(host, port)
loop do
ready = IO.select([socket, @pipe_r])
if ready[0].include?(@pipe_r)
data_to_send = @pipe_r.read_nonblock(1024)
socket.write(data_to_send)
end
if ready[0].include?(socket)
data_received = socket.read_nonblock(1024)
h2 << data_received
break if socket.nil? || socket.closed? || socket.eof?
end
end
end
end
これは美しく機能しますが、例のように法線でのみ機能TCPSocket
します。IO.select docsOpenSSL::SSL::SSLSocket
に従って、代わりにを使用する必要があります。
IO.select を使用する最善の方法は、read_nonblock、write_nonblock などのノンブロッキング メソッドの後に呼び出すことです。
[...]
特に、ノンブロッキング メソッドと IO.select の組み合わせは、OpenSSL::SSL::SSLSocket などの IO のようなオブジェクトに適しています。
これによると、ノンブロッキング メソッドのIO.select
後に呼び出す必要がありますが、ループでは以前に使用しているため、2 つの異なる IO オブジェクトから選択できます。
IO.select
SSL ソケットでの使用方法の例は次のとおりです。
begin
result = socket.read_nonblock(1024)
rescue IO::WaitReadable
IO.select([socket])
retry
rescue IO::WaitWritable
IO.select(nil, [socket])
retry
end
ただし、これは が単一のIO オブジェクトIO.select
で使用されている場合にのみ機能します。
@pipe_r
私の質問は、とsocket
オブジェクトの両方から選択する必要がある場合、前の例を SSL ソケットで機能させるにはどうすればよいですか?
編集: @steffen-ullrich が提案したことを試しましたが、役に立ちませんでした。以下を使用して、テストに合格することができました。
loop do
begin
data_to_send = @pipe_r.read_nonblock(1024)
socket.write(data_to_send)
rescue IO::WaitReadable, IO::WaitWritable
end
begin
data_received = socket.read_nonblock(1024)
h2 << data_received
break if socket.nil? || socket.closed? || socket.eof?
rescue IO::WaitReadable
IO.select([socket, @pipe_r])
rescue IO::WaitWritable
IO.select([@pipe_r], [socket])
end
end
これはそれほど悪くはありませんが、どんな入力も歓迎します。