Как сделать неблокирующее чтение на не-сокете FD - PullRequest
0 голосов
/ 07 декабря 2018

Есть ли способ сделать single read() в неблокирующем режиме на канале / терминале / и т. Д., Как я могу сделать это на сокете с recv(MSG_DONTWAIT)?

Причина, по которой мне это нужно, заключается в том, что я не могу найти никакой гарантии, что read() в дескрипторе файла, возвращенном как готовый к чтению select() или poll(), будет не блоком.

Я знаю, что дескриптор файла может быть неблокирующим с помощью fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK), но это изменит режим для этого файлового дескриптора глобально, а не только в вызывающем потоке / процессе.Например:

% perl -MFcntl=F_SETFL,F_GETFL,O_NONBLOCK -e 'fcntl STDIN, F_SETFL, fcntl(STDIN, F_GETFL, 0) | O_NONBLOCK; select undef, undef, undef, undef'
^Z # put it in the background
% cat
cat: -: Resource temporarily unavailable

Это также сделает fd неблокирующим для и чтения и записи, что может запутать ад из другого процесса, выполняющего противоположное действие на том же самом fd, так какin:

non_blocking_read | filter | blocking_write

Один из способов, который я думаю, это сохранить флаги состояния файла при запуске и SIGCONT и восстановить их при выходе и SIGTSTP (так же, как это делается с помощью termiosнастройки), но это очень ограниченно, склонно к гонкам и оставит беспорядок в случае ненормального выхода из программы.

Установка сохранения / восстановления с помощью fcntl() до / после каждого read()также чувствует себя уродливым и тупым, и может иметь и другие проблемы.То же самое с ioctl(FIONREAD) как раз перед read (который я даже не уверен, что он будет надежно работать с любым fd; гарантии в этом направлении будут приветствоваться, хотя).

Я был бы счастливдаже с системными (например, linux или bsd-only) решениями.

Для справки здесь - это обсуждение исправления в linux;эта идея, похоже, никуда не делась.

1 Ответ

0 голосов
/ 07 декабря 2018

Единственным решением для Linux было бы повторно открыть дескриптор файла через "/ dev / stdin" | "/ dev / tty" | "/ dev / fd / $ fd" .

C пример:

#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
int main()
{
    int fd;
    char buf[8];
    int flags;
    if(0>(fd=open("/dev/stdin", O_RDONLY))) return 1;
    if(0>(flags = fcntl(fd,F_GETFL))) return 1;
    if(0>(flags = fcntl(fd,F_SETFL,flags|O_NONBLOCK))) return 1;
    sleep(3);
    puts("reading");
    ssize_t nr = read(fd, buf, sizeof(buf));
    printf("read=%zd\n", nr);
    return 0;
}

В отличие от dup лицензированного файлового дескриптора, вновь открытый файловый дескриптор будет иметь независимые флаги состояния файла.

...