IO#read blocks on non-blocking socket?

问题描述 投票:0回答:1

红宝石 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 ()
1 0xb7e5539d in select () from /lib/tls/i686/cmov/libc.so.6
2 0x08064368 in rb_thread_schedule () 在 eval.c:11020
3 0x080785bb in io_fread (

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

ruby sockets nonblocking
1个回答
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 中可用。
© www.soinside.com 2019 - 2024. All rights reserved.