Книга: UNIX: разработка сетевых приложений
7.11. Функция fcntl
Разделы на этой странице:
7.11. Функция fcntl
Сокращение fcntl
означает «управление файлами» (file control). Эта функция выполняет различные операции управления дескрипторами. Перед описанием этой функции и ее влияния на сокет нам нужно составить некоторое более общее представление о ее возможностях. В табл. 7.9 приводятся различные операции, выполняемые функциями fcntl
и ioctl
и маршрутизирующими сокетами.
Таблица 7.9. Операции функций fcntl и ioctl и маршрутизирующих сокетов
Операция | fcntl | ioctl | Маршрутизирующий сокет | Posix.1g |
---|---|---|---|---|
Установка сокета для неблокируемого ввода-вывода | F_SETFL, O_NONBLOCK | FIONBIO | fcntl | |
Установка сокета для ввода-вывода, управляемого сигналом | F_SETFL, O_ASYNC | FIOASYNC | fcntl | |
Установка владельца сокета | F_SETOWN | SIOCSPGRP или FIOSETOWN | fcntl | |
Получение владельца сокета | F_GETOWN | SIOCGPGRP или FIOGETOWN | fcntl | |
Получение текущего количества байтов в приемном буфере сокета | FIONREAD | |||
Проверка, находится ли процесс на отметке внеполосных данных | SIOCATMARK | sockatmark | ||
Получение списка интерфейсов | SIOCGIFCONF | Sysctl | ||
Операции интерфейсов | SIOC[GS]IFxxx | |||
Кэш-операции ARP | SIOCxARP | RTM_xxx | ||
Операции таблицы маршрутизации | SIOGxxxRT | RTM_xxx |
Первые шесть операций могут применяться к сокетам любым процессом, следующие две (операции над интерфейсами) используются реже, а последние две (ARP и таблица маршрутизации) выполняются администрирующими программами, такими как ifconfig
и route
. О различных операциях функции ioctl
мы поговорим подробнее в главе 17, а о маршрутизирующих сокетах — в главе 18.
Существует множество способов выполнения первых четырех операций, но, как указано в последней колонке, стандарт POSIX определяет, что функция fcntl
является предпочтительным способом. Отметим также, что POSIX предлагает функцию sockatmark
(см. раздел 24.3) как наиболее предпочтительный способ тестирования на предмет пребывания процесса на отметке внеполосных данных. Оставшиеся операции с пустой последней колонкой не стандартизованы POSIX.
ПРИМЕЧАНИЕ
Отметим также, что первые две операции, устанавливающие сокет для неблокируемого ввода-вывода и для ввода-вывода, управляемого сигналом, традиционно применялись с использованием команд FNDELAY и FASYNC функции fcntl. POSIX определяет константы О_xxx.
Функция fcntl
предоставляет следующие возможности, относящиеся к сетевому программированию:
? Неблокируемый ввод-вывод. Мы можем установить флаг состояния файла O_NONBLOCK
, используя команду F_SETFL
для отключения блокировки сокета. Неблокируемый ввод-вывод мы описываем в главе 16.
? Управляемый сигналом ввод-вывод. Мы можем установить флаг состояния файла O_ASYNC
, используя команду F_SETFL
, после чего при изменении состояния сокета будет генерироваться сигнал SIGIO. Мы рассмотрим это в главе 25.
? Команда F_SETOWN
позволяет нам установить владельца сокета (идентификатор процесса или идентификатор группы процессов), который будет получать сигналы SIGIO
и SIGURG
. Первый сигнал генерируется, если для сокета включен управляемый сигналом ввод-вывод (см. главу 25), второй — когда для сокета приходят новые внеполосные (out-of-band data) данные (см. главу 24). Команда F_GETOWN
возвращает текущего владельца сокета.
ПРИМЕЧАНИЕ
Термин «владелец сокета» определяется POSIX. Исторически реализации, происходящие от Беркли, называли его «идентификатор группы процессов сокета», потому что переменная, хранящая этот идентификатор, — это элемент so_pgid структуры socket [128, с. 438].
#include <fcntl.h>
int fcntl(int fd, int cmd, ... /* int arg */);
Возвращает: в случае успешного выполнения результат зависит от аргумента cmd, -1 в случае ошибки
Каждый дескриптор (включая сокет) имеет набор флагов, которые можно получить с помощью команды F_GETFL
и установить с помощью команды F_SETFL
. На сокет влияют следующие два флага:
? O_NONBLOCK
— неблокируемый ввод-вывод;
? O_ASYNC
— ввод-вывод, управляемый сигналом.
Позже мы опишем оба эти флага подробнее. Отметим, что типичный код, который устанавливает неблокируемый ввод-вывод с использованием функции fcntl
, выглядит следующим образом:
int flags;
/* Делаем сокет неблокируемым */
if ((flags = fcntl(fd, F_GETFL, 0)) < 0)
err_sys("F_GETFL error");
flags |= O_NONBLOCK;
if (fcntl(fd, F_SETFL, flags) < 0)
err_sys("F_SETFL error");
Учтите, что вам может встретиться код, который просто устанавливает желаемый флаг:
/* Неправильный способ сделать сокет неблокируемым */
if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0)
err_sys("F_SETFL error");
Хотя при этом и устанавливается флаг отключения блокировки, также снимаются все остальные флаги состояния файла. Единственный корректный способ установить один из этих флагов состояния файла — получить текущие флаги, с помощью операции логического ИЛИ добавить новый флаг, а затем установить флаги.
Следующий код сбрасывает флаг отключения блокировки в предположении, что переменная flags
была задана с помощью вызова функции fcntl
, показанного ранее:
flags &= ~O_NONBLOCK;
if (fcntl(fd, F_SETFL, flags) < 0)
err_sys("F_SETFL error");
Сигналы SIGIO
и SIGURG
отличаются от других тем, что они генерируются для сокета, только если сокету был присвоен владелец с помощью команды F_SETOWN
. Целое значение аргумента arg
для команды F_SETOWN
может быть либо положительным, задающим идентификатор процесса, получающего сигнал, либо отрицательным, абсолютное значение которого — это идентификатор группы процессов, получающей сигнал. Команда F_GETOWN
возвращает владельца сокета, так как возвращаемое значение функции fcntl
— либо идентификатор процесса (положительное возвращаемое значение), либо идентификатор группы процессов (отрицательное значение, отличное от -1). Разница между заданием процесса и группы процессов, получающих сигнал, в том, что в первом случае сигнал будет получен только одиночным процессом, тогда как во втором случае его получают все процессы в группе.
Когда создается новый сокет с помощью функции socket, у него нет владельца. Сокет, создаваемый из прослушиваемого сокета, наследует от него принадлежность владельцу (как и многие другие параметры сокетов [128, с. 462-463].
- 7.1. Введение
- 7.2. Функции getsockopt и setsockopt
- 7.3. Проверка наличия параметра и получение значения по умолчанию
- 7.4. Состояния сокетов
- 7.5. Общие параметры сокетов
- 7.6. Параметры сокетов IPv4
- 7.7. Параметр сокета ICMPv6
- 7.8. Параметры сокетов IPv6
- 7.9. Параметры сокетов TCP
- 7.10. Параметры сокетов SCTP
- 7.11. Функция fcntl
- 7.12. Резюме
- Упражнения
- 9.4.3. Управление атрибутами файла: fcntl()
- 9.4.3.5. Сводка fcntl()
- Функция close(2)
- Функция read(2) и readv(2)
- Функция fcntl(2)
- 4.9. Функция close
- fcntl
- 8.3. Функция fcntl(): блокировки и другие операции над файлами
- 2.1.3. Функция getopt_long()
- Группировка по встроенным функциям и UDF
- 19.1.1. Функция jQuery()
- Функция strcmp( )