本文简要介绍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。非经特殊声明,原始代码版权归原作者所有,本译文未经允许或授权,请勿转载或复制。