本文簡要介紹ruby語言中 IO.select
的用法。
用法
select(read_array [, write_array [, error_array [, timeout]]]) → array or nil
調用 select(2) 係統調用。它監視給定的 IO
對象數組,等待一個或多個 IO
對象準備好讀取、準備好寫入並分別有未決異常,並返回一個包含這些 IO
對象數組的數組。如果給出可選的timeout
值並且在timeout
秒內沒有 IO
對象準備好,它將返回nil
。
IO.select
查看 IO
對象的緩衝區以測試可讀性。如果 IO
緩衝區不為空, IO.select
會立即通知可讀性。此 “peek” 僅發生在 IO
對象上。對於 IO-like 對象(例如 OpenSSL::SSL::SSLSocket
)不會發生這種情況。
使用 IO.select
的最佳方法是在 read_nonblock
、 write_nonblock
等非阻塞方法之後調用它。這些方法會引發由 IO::WaitReadable
或 IO::WaitWritable
擴展的異常。模塊通知調用者應該如何等待 IO.select
。如果引發 IO::WaitReadable
,調用者應該等待讀取。如果引發 IO::WaitWritable
,調用者應該等待寫入。
因此,可以使用 read_nonblock
和 IO.select
模擬阻塞讀取 ( readpartial
),如下所示:
begin
result = io_like.read_nonblock(maxlen)
rescue IO::WaitReadable
IO.select([io_like])
retry
rescue IO::WaitWritable
IO.select(nil, [io_like])
retry
end
特別是,非阻塞方法和 IO.select
的組合對於 IO
類對象(如 OpenSSL::SSL::SSLSocket
)是首選。它具有 to_io
方法來返回底層 IO
對象。 IO.select
調用 to_io
獲取要等待的文件說明符。
這意味著 IO.select
通知的可讀性並不意味著 OpenSSL::SSL::SSLSocket
對象的可讀性。
最可能的情況是 OpenSSL::SSL::SSLSocket
緩衝了一些數據。 IO.select
看不到緩衝區。因此,當 OpenSSL::SSL::SSLSocket#readpartial
不阻塞時, IO.select
可以阻塞。
但是,存在幾種更複雜的情況。
SSL 是一種記錄序列的協議。記錄由多個字節組成。因此,SSL 的遠程端發送部分記錄, IO.select
通知可讀性但 OpenSSL::SSL::SSLSocket
無法解密字節並且 OpenSSL::SSL::SSLSocket#readpartial
將阻塞。
此外,遠程端可以請求 SSL 重新協商,這會強製本地 SSL 引擎寫入一些數據。這意味著 OpenSSL::SSL::SSLSocket#readpartial
可以調用 write
係統調用並且它可以阻塞。在這種情況下, OpenSSL::SSL::SSLSocket#read_nonblock
引發 IO::WaitWritable
而不是阻塞。因此,調用者應該等待準備好寫,如上例所示。
當多個進程從一個流中讀取時,非阻塞方法和 IO.select
的組合對於 tty、管道套接字套接字等流也很有用。
最後,Linux 內核開發人員不保證 select(2) 的可讀性意味著即使對於單個進程也可以遵循 read(2) 的可讀性。請參閱 GNU/Linux 係統上的 select(2) 手冊。
在 IO#readpartial
之前調用 IO.select
可以正常工作。但是,這不是使用 IO.select
的最佳方式。
select(2) 通知的可寫性不顯示可寫的字節數。 IO#write
方法阻塞,直到給定的整個字符串被寫入。因此,在 IO.select
通知可寫性後,IO#write(two or more bytes)
可以阻塞。需要 IO#write_nonblock
以避免阻塞。
可以使用 write_nonblock
和 IO.select
模擬阻塞寫入 ( write
),如下所示: IO::WaitReadable
還應該在 OpenSSL::SSL::SSLSocket
中為 SSL 重新協商而拯救。
while 0 < string.bytesize
begin
written = io_like.write_nonblock(string)
rescue IO::WaitReadable
IO.select([io_like])
retry
rescue IO::WaitWritable
IO.select(nil, [io_like])
retry
end
string = string.byteslice(written..-1)
end
參數
示例
rp, wp = IO.pipe
mesg = "ping "
100.times {
# IO.select follows IO#read. Not the best way to use IO.select.
rs, ws, = IO.select([rp], [wp])
if r = rs[0]
ret = r.read(5)
print ret
case ret
when /ping/
mesg = "pong\n"
when /pong/
mesg = "ping "
end
end
if w = ws[0]
w.write(mesg)
end
}
產生:
ping pong
ping pong
ping pong
(snipped)
ping
相關用法
- Ruby IO.self << object用法及代碼示例
- Ruby IO.set_encoding_by_bom用法及代碼示例
- Ruby IO.seek用法及代碼示例
- Ruby IO.syswrite用法及代碼示例
- Ruby IO.stat用法及代碼示例
- Ruby IO.sysopen用法及代碼示例
- Ruby IO.sysseek用法及代碼示例
- Ruby IO.sync =用法及代碼示例
- Ruby IO.sync用法及代碼示例
- Ruby IO.sysread用法及代碼示例
- Ruby IO.eof用法及代碼示例
- Ruby IO.read用法及代碼示例
- Ruby IO.fileno用法及代碼示例
- Ruby IO.pread用法及代碼示例
- Ruby IO.raw用法及代碼示例
- Ruby IO.readlines用法及代碼示例
- Ruby IO.to_i用法及代碼示例
- Ruby IO.tty?用法及代碼示例
- Ruby IO.close_write用法及代碼示例
- Ruby IO.write_nonblock用法及代碼示例
- Ruby IO.close_read用法及代碼示例
- Ruby IO.pwrite用法及代碼示例
- Ruby IO.ungetc用法及代碼示例
- Ruby IO.noecho用法及代碼示例
- Ruby IO.new用法及代碼示例
注:本文由純淨天空篩選整理自ruby-lang.org大神的英文原創作品 IO.select。非經特殊聲明,原始代碼版權歸原作者所有,本譯文未經允許或授權,請勿轉載或複製。