erstellen Ich baue eine Client-Ruby-Bibliothek, die eine Verbindung zu einem Server herstellt und auf Daten wartet, aber auch Benutzer Daten durch Aufruf einer Methode senden können.Wie kann ich einen Zwei-Wege-SSL-Socket in Ruby
Der Mechanismus I verwenden, um eine Klasse zu haben, die ein Buchsenpaar initialisiert, etwa so:
def initialize
@pipe_r, @pipe_w = Socket.pair(:UNIX, :STREAM, 0)
end
Die Methode, die ich Entwicklern ermöglichen, rufen Daten sieht wie folgt aus, um den Server zu senden:
def send(data)
@pipe_w.write(data)
@pipe_w.flush
end
Dann habe ich eine Schleife in einem separaten Thread, wo ich aus einem socket
wählen mit dem Server verbunden und von den @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
Dies funktioniert wunderbar, aber nur mit einer normalen TCPSocket
wie im Beispiel. Ich brauche ein OpenSSL::SSL::SSLSocket
stattdessen verwenden, aber nach the IO.select docs:
Der beste Weg, IO.select zu verwenden ist es nach nonblocking Methoden wie read_nonblock Aufruf, write_nonblock usw.
[...]
Insbesondere die Kombination von nonblocking-Methoden und IO.select wird für IO wie Objekte wie OpenSSL :: SSL :: SSLSocket bevorzugt.
Nach diesem, ich brauche IO.select
nach nonblocking Methoden aufrufen, während in meiner Schleife ich es verwenden vor so kann ich aus zwei verschiedenen IO-Objekte auswählen.
Das gegebene Beispiel dafür, wie IO.select
mit einer SSL-Socket zu verwenden ist:
begin
result = socket.read_nonblock(1024)
rescue IO::WaitReadable
IO.select([socket])
retry
rescue IO::WaitWritable
IO.select(nil, [socket])
retry
end
Dies funktioniert jedoch nur, wenn IO.select
mit einem einzigen IO-Objekt verwendet wird.
Meine Frage ist: Wie kann ich mein vorheriges Beispiel mit einem SSL-Socket arbeiten, vorausgesetzt, dass ich aus den @pipe_r
und den socket
Objekten auswählen muss?
EDIT: Ich habe versucht, was @ Steffen-Ullrich vorgeschlagen, jedoch ohne Erfolg. Ich konnte meine Tests bestanden mit dem folgenden machen:
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
Dies sieht nicht so schlecht, aber jeder Eingang ist willkommen.
Vielen Dank @ Steffen-Ullrich, das ist eine sehr klare Antwort. Leider habe ich versucht, die ausstehende Methode zu verwenden, bevor ich select benutze, und ich bekomme immer, dass 0 Bytes verfügbar sind. Ich habe auch nonblock_read (32768) versucht und das tut auch nicht den Trick. Werde mehr versuchen. – ostinelli
Wird diese Antwort akzeptieren, da sie den richtigen Weg zur Lösung dieser Probleme verdeutlicht. Danke nochmal! – ostinelli