[英]What's the best way to escape from Ruby's TCPSocket::gets after a given timeout?
我有以下(簡化的)ruby 代碼,它打開 ruby 的 TCP-Socket 並從中讀取:
socket = TCPSocket.open(server, port)
while line = socket.gets
line = line.chop
end
現在我只想在給定的時間段(即 1 分鍾)內從套接字讀取數據。 所以在 1 分鍾后,while 塊應該被打破並且進程應該退出。
把一行像
break if (elapsed_time > 1000)
進入gets
塊是不可能的,因為如果沒有任何內容寫入套接字,則不會到達這行代碼。
謝謝
要以非阻塞方式從 IO 讀取數據,可以使用read_nonblock
。 如果 IO 未准備好讀取,它要么讀取可用字節(達到給定的最大值),要么引發異常。 異常解救后,可以調用IO.select
等待IO准備好讀取。
IO.select
最多占用 3 個 arrays 和 IOs 來監視 1) 讀取,2) 寫入和 3) 異常(您可以一次監視多個 IOs)。 一個基本的循環看起來像這樣:
buffer = String.new
loop do
begin
buffer << socket.read_nonblock(1024)
rescue IO::WaitReadable
IO.select([socket])
end
end
以上嘗試讀取最多 1024 個字節,這些字節將被附加到buffer
。 如果讀取成功,它將讀取接下來的 1024 個字節,依此類推。 如果由於套接字沒有任何數據而導致讀取失敗,它會調用IO.select
來監視套接字並在有更多數據可用時立即返回。
IO.select
也需要第 4 個參數timeout
。 如果超過給定值(以秒為單位),它將返回nil
,可用於有條件地break
循環:
loop do
begin
buffer << socket.read_nonblock(1024)
rescue IO::WaitReadable
break unless IO.select([socket], nil, nil, 10)
end
end
以上將等待最多 10 秒,以便更多數據可用,否則會中斷循環。
但是,每次(失敗的)讀取嘗試都會等待 10 秒。 要獲得整個循環的“全局”超時,您可能需要遵循以下原則:
timeout = 10
buffer = String.new
t = Time.now
remaining = timeout
while remaining > 0
begin
buffer << socket.read_nonblock(1024)
rescue IO::WaitReadable
break unless IO.select([socket], nil, nil, remaining)
end
elapsed = Time.now - t
remaining = timeout - elapsed
end
上面跟蹤剩余時間(以秒為單位)並將該值作為超時傳遞給IO.select
。
最后,您可能希望在行可用時立即對其進行處理。 為此,您可以檢查字符串緩沖區中的換行符並通過slice!
(可能在一個循環中,因為您可能一次閱讀了多行)。 然后可以生成每條提取的行:
def gets_while(io, timeout)
buffer = String.new
t = Time.now
remaining = timeout
while remaining > 0
begin
buffer << io.read_nonblock(1024)
while (newline = buffer.index("\n"))
yield buffer.slice!(0..newline)
end
rescue IO::WaitReadable
break unless IO.select([io], nil, nil, remaining)
rescue EOFError
break # end of stream / connection closed
end
elapsed = Time.now - t
remaining = timeout - elapsed
end
end
用法示例:
socket = TCPSocket.open(server, port)
gets_while(socket, 60) do |line|
l = line.chomp
# ...
end
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.