UNIX: разработка сетевых приложений
POSIX определяет функцию
(повышающую точность таймера с микросекунд до наносекунд) которой передается новый аргумент — указатель на набор сигналов. Это позволяет избежать ситуации гонок (race condition) при перехвате сигналов, о которой мы поговорим более подробно в разделе 20.5.pselectФункция
из System V предоставляет функциональность, аналогичную функцииpoll. Кроме того, она обеспечивает дополнительную информацию при работе с потоковыми устройствами. POSIX требует наличия и функцииselect, и функцииselect, но первая распространена шире.pollУпражнения
1. Мы говорили, что набор дескрипторов можно присвоить другому набору дескрипторов, используя оператор присваивания языка С. Как это сделать, если набор дескрипторов является массивом целых чисел? (Подсказка: посмотрите на свой системный заголовочный файл
или<sys/select.h>.)<sys/types.h>2. Описывая в разделе 6.3 условия, при которых функция
сообщает, что дескриптор готов для записи, мы указали, что сокет должен быть неблокируемым, для того чтобы операция записи возвратила положительное значение. Почему?select3. Что произойдет с программой из листинга 6.1, если мы поставим слово
передelseв строке 19?if4. В листинге 6.3 добавьте необходимый код, чтобы позволить серверу использовать максимальное число дескрипторов, допустимое ядром (Подсказка: изучите функцию
.)setrlimit5. Посмотрите, что происходит, если в качестве второго аргумента функции
передаетсяshutdown. Возьмите за основу код клиента TCP, представленный в листинге 5.3, и выполните следующие изменения: вместо номера портаSHUT_RDзадайте порт 19 (службаSERV_PORT, см. табл. 2.1), а также замените вызов функцииchargenвызовом функцииstr_cli. Запустите программу, задав IP-адрес локального узла, на котором выполняется серверpause. Просмотрите пакеты с помощью такой программы, как, например,chargen(см. раздел В.5). Что происходит?tcpdump6. Почему приложение должно вызывать функцию
с аргументомshutdown, вместо того чтобы просто вызвать функциюSHUT_RDWR?close7. Что происходит в листинге 6.4, когда клиент отправляет RST для завершения соединения?
8. Перепишите код, показанный в листинге 6.5, чтобы вызывать функцию
для определения максимального числа дескрипторов и размещения соответствующего массиваsysconfв памяти.clientГлава 7
Параметры сокетов
7.1. Введение
Существуют различные способы получения и установки параметров сокетов:
■ функции
иgetsockopt;setsockopt■ функция
;fcntl■ функция
.ioctlЭту главу мы начнем с описания функций
иgetsockopt. Далее мы приведем пример, в котором выводятся заданные по умолчанию значения параметров, а затем дадим подробное описание всех параметров сокетов. Мы разделили описание параметров на следующие категории: общие, IPv4, IPv6, TCP и SCTP. При первом прочтении главы можно пропустить подробное описание параметров и при необходимости прочесть отдельные разделы, на которые даны ссылки. Отдельные параметры подробно описываются в дальнейших главах, например параметры многоадресной передачи IPv4 и IPv6 мы обсуждаем в разделе 19.5.setsockoptМы также рассмотрим функцию
, поскольку она реализует предусмотренные стандартом POSIX возможности отключить для сокета блокировку ввода-вывода, включить управление сигналами, а также установить владельца сокета. Функциюfcntlмы опишем в главе 17.ioctl7.2. Функции getsockopt и setsockopt
Эти две функции применяются только к сокетам.
#include <sys/socket.h>int getsockopt(int <i>sockfd</i>, int <i>level</i>, int <i>optname</i>, void *<i>optval</i>, socklen_t *<i>optlen</i>);int setsockopt(int <i>sockfd</i>, int <i>level</i>, int <i>optname</i>, const void *<i>optval</i>, socklen_t <i>optlen</i>);<i>Обе функции возвращают 0 в случае успешного завершения, -1 в случае ошибки</i>Переменная
должна ссылаться на открытый дескриптор сокета. Переменнаяsockfdопределяет, каким кодом должен интерпретироваться параметр: общими программами обработки сокетов или зависящими от протокола программами (например, IPv4, IPv6, TCP или SCTP).level— это указатель на переменную, из которой извлекается новое значение параметра с помощью функцииoptvalили в которой сохраняется текущее значение параметра с помощью функцииsetsockopt. Размер этой переменной задается последним аргументом. Для функцииgetsockoptтип этого аргумента — значение, а для функцииsetsockopt— «значение-результат».getsockoptВ табл. 7.1 и 7.2 сведены параметры, которые могут запрашиваться функцией
или устанавливаться функциейgetsockopt. В колонке «Тип данных» приводится тип данных того, на что указывает указательsetsockoptдля каждого параметра. Две фигурные скобки мы используем, чтобы обозначить структуру, напримерoptvalобозначаетlinger{}.struct lingerТаблица 7.1. Параметры сокетов для функций getsockopt и setsockopt
level optname get set Описание Флаг Тип данных SOL_SOCKET SO_BROADCAST • • Позволяет посылать широковещательные дейтаграммы • int SO_DEBUG • • Разрешает отладку • int SO_DONTROUTE • • Обходит таблицу маршрутизации • int SO_ERROR • Получает ошибку, ожидающую обработки, и возвращает значение параметра в исходное состояние int SO_KEEPALIVE • • Периодически проверяет, находится ли соединение в рабочем состоянии • int SO_LINGER • • Задерживает закрытие сокета, если имеются данные для отправки linger{} SO_OOBINLINE • • Оставляет полученные внеполосные данные вместе с обычными данными (inline) • int SO_RCVBUF • • Размер приемного буфера int SO_SNDBUF • • Размер буфера отправки int SO_RCVLOWAT • • Минимальное количество данных для приемного буфера сокета int SO_SNDLOWAT • • Минимальное количество данных для буфера отправки сокета int SO_RCVTIMEO • • Тайм-аут при получении timeval{} SO_SNDTIMEO • • Тайм-аут при отправке timeval{} SO_REUSEADDR • • Допускает повторное использование локального адреса • int SO_REUSEPORT • • Допускает повторное использование локального адреса • int SO_TYPE • Возвращает тип сокета int SO_USELOOPBACK • • Маршрутизирующий сокет получает копию того, что он отправляет • int IPPROTO_IP IP_HDRINCL • • Включается IP- заголовок • int IP_OPTIONS • • В заголовке IPv4 устанавливаются параметры IP см. текст IP_RECVDSTADDR • • Возвращает IP-адрес получателя • int IP_RECVIF • • Возвращает индекс интерфейса, на котором принимается дейтаграмма UDP • int IP_TOS • • Тип сервиса и приоритет int IP_TTL • • Время жизни int IP_MULTICAST_IF • • Задает интерфейс для исходящих дейтаграмм in_addr{} IP_MULTICAST_TTL • • Задает TTL для исходящих дейтаграмм u_char IP_MULTICAST_LOOP • • Разрешает или отменяет отправку копии дейтаграммы на тот узел, откуда она была послана (loopback) u_char IP_ADD_MEMBERSHIP • Включение в группу многоадресной передачи ip_mreq{} IP_DROP_MEMBERSHIP • Отключение от группы многоадресной передачи ip_mreq{} IP_{BLOCK, UNBLOCK}_SOURCE • Блокирование и разблокирование источника многоадресной передачи ip_mreq_source{} IP_{ADD, DROP}_SOURCE_MEMBERSHIP • Присоединение или отключение от многоадресной передачи от источника (source-specific) ip_mreq_source{} IPPROTO_ICMPV6 ICMP6_FILTER • • Указывает тип сообщения ICMPv6, которое передается процессу icmp6_filter{} IPPROTO_IPV6 IPV6_ADDRFORM • • Меняет формат адреса сокета int IPV6_CHECKSUM • • Отступ поля контрольной суммы для символьных (неструктурированных) сокетов int IPV6_DONTFRAG • • Не фрагментировать, а сбрасывать большие пакеты • int IPV6_NEXTHOP • • Задает следующий транзитный адрес • sockaddr{} IPV6_PATHMTU • Получение текущей маршрутной МТУ ip6_mtuinfo{} IPV6_RECVDSTOPTS • • Получение параметров адресата • int IPV6_RECVHOPLIMIT • • Получение ограничения на количество транзитных узлов при направленной передаче • int IPV6_RECVHOPOPTS • • Получение параметров прыжков • int IPV6_RECVPATHMTU • • Получение маршрутной MTU • int IPV6_RECVPKTINFO • • Получение информации о пакетах • int IPV6_RECVRTHDR • • Получение маршрута от источника • int IPV6_RECVTCLASS • • Получение класса трафика • int IPV6_UNICAST_HOPS • • Предел количества транзитных узлов, задаваемый по умолчанию int IPV6_USE_MIN_MTU • • Использовать минимальную MTU • int IPV6_V60NLY • • Отключить совместимость с IPv4 • int IPV6_XXX • • Вспомогательные данные см. текст IPV6_MULTICAST_IF • • Задает интерфейс для исходящих дейтаграмм u_int IPV6_MULTICAST_HOPS • • Задает предельное количество транзитных узлов для исходящих широковещательных сообщений int IPV6_MULTICAST_LOOP • • Разрешает или отменяет отправку копии дейтаграммы на тот узел, откуда она была послана (loopback) • u_int IPV6_LEAVE_GROUP • Выход из группы многоадресной передачи ipv6_mreq{} IPPROTO_IP или IPPROTO_IPV6 MCAST_JOIN_GROUP • Присоединение к группе многоадресной передачи group_req{} MCAST_LEAVE_GROUP • Выход из группы многоадресной передачи group_source_req{} MCAST_BLOCK_SOURCE • Блокирование источника многоадресной передачи group_source_req{} MCAST_UNBLOCK_SOURCE • Разблокирование источника многоадресной передачи group_source_req{} MCAST_JOIN_SOURCE_GROUP • Присоединение к группе многоадресной передачи от источника group_source_req{} MCAST_LEAVE_SOURCE_GROUP • Выход из группы многоадресной передачи от источника group_source_req{}