Неблокирующий Unix и ввода/вывода: о НЕБЛОКОВЫЙ и FIONBIO
в каждом примере и обсуждении, с которыми я сталкиваюсь в контексте программирования сокетов BSD, кажется, что рекомендуемый способ установить файловый дескриптор в неблокирующий режим ввода-вывода использует O_NONBLOCK
флаг fcntl()
, например,
int flags = fcntl(fd, F_GETFL, 0);
fcntl(fd, F_SETFL, flags | O_NONBLOCK);
Я занимаюсь сетевым программированием в UNIX уже более десяти лет и всегда использовал FIONBIO ioctl()
позвоните, чтобы сделать это:
int opt = 1;
ioctl(fd, FIONBIO, &opt);
никогда не задумывался над тем, почему. Просто научился этому таким образом.
есть ли у кого-нибудь какие-либо комментарии относительно возможных соответствующих достоинств того или другого? Я предполагаю, что локус переносимости несколько отличается, но не знаю, в какой степени, как ioctl_list(2)
не говорит с этим аспектом личности ioctl
методы.
3 ответа:
до стандартизации было
ioctl(
...FIONBIO
...)
иfcntl(
...O_NDELAY
...)
, но они вели себя непоследовательно между системами и даже внутри одной и той же системы. Например, это было распространено дляFIONBIO
работать на сокетах иO_NDELAY
для работы на ttys, с большим количеством несоответствий для таких вещей, как трубы, fifos и устройства. И если вы не знаете, какой файловый дескриптор у вас есть, вам придется установить оба, чтобы быть уверенным. Но кроме того, неблокирующее чтение с данные также не были указаны несогласованно; в зависимости от ОС и типа файлового дескриптора чтение может возвращать 0, или -1 С errno EAGAIN, или -1 С errno EWOULDBLOCK. Даже сегодня, установкаFIONBIO
илиO_NDELAY
на Solaris вызывает чтение без данных, чтобы возвратить 0 на tty или трубе, или -1 С errno EAGAIN на сокете. Однако 0 неоднозначен, так как он также возвращается для EOF.POSIX обратился к этому с введением
O_NONBLOCK
, который имеет стандартизированное поведение в разных системах и типах дескрипторов файлов. Поскольку существующие системы обычно хотят избежать каких-либо изменений в поведении, которые могут нарушить обратную совместимость, POSIX определил новый флаг, а не предписывал определенное поведение для одного из других. Некоторые системы, такие как Linux, обрабатывают все 3 одинаково, а также определяют EAGAIN и EWOULDBLOCK к одному и тому же значению, но системы, желающие поддерживать какое-либо другое устаревшее поведение для обратной совместимости, могут сделать это, когда старые механизмы используемый.новые программы должны использовать
fcntl(
...O_NONBLOCK
...)
, как стандартизировано POSIX.
Я считаю
fcntl()
- это функция POSIX. Где какioctl()
Это стандартная вещь UNIX. Вот список POSIX io.ioctl()
это очень ядро/драйвер/ОС конкретная вещь, но я уверен, что вы используете работает на большинстве вкусов Unix. какой-то другойioctl()
материал может работать только на определенных ОС или даже определенных оборотах его ядра.
как сказал @Sean,
fcntl()
в значительной степени стандартизированы, и, следовательно, доступен для всех платформ. Элементioctl()
функция предшествуетfcntl()
в Unix, но не нормируется вообще. Что заioctl()
работал для вас на всех платформах, имеющих отношение к вам повезло, но не гарантировано. В частности, имена, используемые для второго аргумента, являются тайными и ненадежными на разных платформах. Действительно, они часто уникальны для конкретного драйвера устройства, на который ссылается файловый дескриптор. (Тегioctl()
вызовы, используемые для битового графического устройства, работающего на ICL Perq под управлением PNX (Perq Unix) двадцать лет назад, никогда не переводились ни на что другое в другом месте, например.)