IO#读取非阻塞套接字上的块?

时间:2010-10-19 11:26:13

标签: ruby sockets nonblocking

Ruby 1.8.7。我正在打开一个已经打开并连接的套接字读取:

socket = Socket.new(AF_INET, SOCK_STREAM, 0)
sockaddr = Socket.sockaddr_in(mp.port, mp.ip_address.ip)
begin
  socket.connect_nonblock(sockaddr)
[...]

通过调用select()然后连接第二次查找Errno :: EISCONN来确认连接。

然后我再次调用select 0并且如果返回不是nil我从套接字读取,首先确认它已设置O_NONBLOCK:

 rc = select([socket], nil, nil, 0)
 puts "  select returned: #{rc.pretty_inspect}"
 if rc
   begin
     puts "  reading: #{socket} nonblock: #{socket.fcntl(Fcntl::F_GETFL) & Fcntl::O_NONBLOCK}"
     response = socket.read
     puts "  done reading"
     [...]

这一切都是每分钟循环一次。第一次循环的输出是:

select returned: [[#<Socket:0xb6e0dcb8>], [], []]
reading: #<Socket:0xb6e0dcb8> nonblock: 2048
done reading

然而第二次循环在这里挂起:

select returned: [[#<Socket:0xb6e0dcb8>], [], []]
reading: #<Socket:0xb6e0dcb8> nonblock: 2048

将gdb附加到进程会显示此回溯:

0 0xffffe410在__kernel_vsyscall()中 来自/lib/tls/i686/cmov/libc.so.6的select()中的1 0xb7e5539d
2 0x08064368在rb_thread_schedule()中的eval.c:11020
io_fread中的3 0x080785bb(

通过调用rcvfrom_nonblock替换调用read,有趣的是它没有得到EAGAIN,它实际上是读取数据(正如你所期望的那样从select中返回)。

有什么想法吗?

史蒂夫

1 个答案:

答案 0 :(得分:2)

你应该期待答案“IO#read不尊重基础文件描述符上设置的标志”:

ruby 1.9.3 IO#read

  

请注意,此方法的行为类似于C中的fread()函数。如果需要   像read(2)系统调用这样的行为,考虑readpartial,   read_nonblock和sysread。

我感谢您使用的是1.8,但是

  • 您看到该进程停留在io_fread
  • IO#read_nonblock也可在1.8中使用。