Tôi đang xây dựng thư viện Ruby của máy khách kết nối với máy chủ và chờ dữ liệu, nhưng cũng cho phép người dùng gửi dữ liệu bằng cách gọi một phương thức.Làm cách nào để tạo ổ cắm SSL hai chiều trong Ruby
Cơ chế tôi sử dụng là phải có một lớp học mà khởi một cặp ổ cắm, như vậy:
def initialize
@pipe_r, @pipe_w = Socket.pair(:UNIX, :STREAM, 0)
end
Phương pháp mà tôi cho phép các nhà phát triển để gọi để gửi dữ liệu đến máy chủ trông như thế này:
def send(data)
@pipe_w.write(data)
@pipe_w.flush
end
Sau đó, tôi có một vòng lặp trong một thread riêng biệt, nơi tôi chọn từ một socket
kết nối với máy chủ và từ @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
Công trình này đẹp, chỉ nhưng chỉ với một ví dụ bình thường TCPSocket
. Tôi cần phải sử dụng một OpenSSL::SSL::SSLSocket
thay vào đó, tuy nhiên theo the IO.select docs:
Cách tốt nhất để sử dụng IO.select là cách gọi nó sau khi phương pháp nonblocking như read_nonblock, write_nonblock vv
[...]
Đặc biệt, kết hợp các phương pháp không chặn và IO.select được ưu tiên cho IO như các đối tượng như OpenSSL :: SSL :: SSLSocket.
Theo điều này, tôi cần phải gọi IO.select
sau phương pháp nonblocking, trong khi trong vòng lặp của tôi, tôi sử dụng nó trước vì vậy tôi có thể chọn từ 2 đối tượng IO khác nhau.
Ví dụ được đưa về cách sử dụng IO.select
với một ổ cắm SSL là:
begin
result = socket.read_nonblock(1024)
rescue IO::WaitReadable
IO.select([socket])
retry
rescue IO::WaitWritable
IO.select(nil, [socket])
retry
end
Tuy nhiên việc này chỉ khi IO.select
được sử dụng với một đơn đối tượng IO .
Câu hỏi của tôi là: làm cách nào để làm ví dụ trước của tôi hoạt động với ổ cắm SSL, cho rằng tôi cần chọn từ cả hai đối tượng @pipe_r
và socket
?
EDIT: Tôi đã thử những gì @ steffen-ullrich đề xuất, tuy nhiên không có kết quả. Tôi đã có thể thực hiện các thử nghiệm của mình bằng cách sử dụng các mục sau:
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
Điều này không quá tệ, nhưng mọi đầu vào đều được chào đón.
Cảm ơn bạn @ steffen-ullrich, đây là câu trả lời rất rõ ràng. Rất tiếc, tôi đã thử sử dụng phương thức đang chờ xử lý trước khi sử dụng chọn và tôi luôn nhận được rằng có sẵn 0 byte. Tôi cũng đã thử nonblock_read (32768) và đó không phải là lừa. Sẽ thử một số chi tiết. – ostinelli
Sẽ chấp nhận câu trả lời này vì nó làm rõ cách chính xác để giải quyết những vấn đề này. Cám ơn bạn một lần nữa! – ostinelli