IO # читать блоки на неблокирующем сокете? - PullRequest
4 голосов
/ 19 октября 2010

Рубин 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 в select () из /lib/tls/i686/cmov/libc.so.6
2 0x08064368 в rb_thread_schedule () на eval.c: 11020
3 0x080785bb в io_fread (

Замена вызова read на вызов rcvfrom_nonblock работает, и, что интересно, он не получает EAGAIN, он фактически читает данные (как и следовало ожидать, учитывая возврат из select).

Есть идеи?

стив

1 Ответ

2 голосов
/ 08 ноября 2011

Вы были правы, ожидая, что ответ "IO # read не учитывает флаги, установленные в базовом файловом дескрипторе":

ruby ​​1.9.3 IO # read

Обратите внимание, что этот метод ведет себя как функция fread () в C. Если вам нужно поведение, подобное системному вызову read (2), рассмотрите readpartial, read_nonblock и sysread.

Я ценю этовы используете 1.8, но

  • вы видите, что процесс застрял в io_fread, и
  • IO#read_nonblock также доступен в версии 1.8.
...