Четыре функции, передающие структуру адреса сокета от процесса к ядру, — bind, connect, sendto и sendmsg — используют функцию sockargs в реализациях, ведущих происхождение от Беркли [128, с. 452]. Эта функция копирует структуру адреса сокета из процесса и затем явно присваивает элементу sin_len значение размера структуры, переданной в качестве аргумента этим четырем функциям. Пять функций, передающих структуру адреса сокета от ядра к процессу, — accept, recvfrom, recvmsg, getpeername и getsockname — устанавливают элемент sin_len перед возвращением управления процессу.
К сожалению, обычно не существует простого теста, выполняемого в процессе компиляции и определяющего, задает ли реализация поле длины для своих структур адреса сокета. В нашем коде мы тестируем собственную константу HAVE_SOCKADDR_SA_LEN (см. листинг Г.2), но для того чтобы определить, задавать эту константу или нет, требуется откомпилировать простую тестовую программу, использующую необязательный элемент структуры, и проверить, успешно ли выполнена компиляция. В листинге 3.3 мы увидим, что от реализаций IPv6 требуется задавать SIN6_LEN, если структура адреса сокета имеет поле длины. В некоторых реализациях IPv4 (например, Digital Unix) поле длины предоставляется для приложений, основанных на параметре времени компиляции (например, _SOCKADDR_LEN). Это свойство обеспечивает совместимость с другими, более ранними программами.
POSIX требует наличия только трех элементов структуры:
sin_family
,
sin_addr
и
sin_port
. POSIX-совместимая реализация может определять дополнительные элементы структуры, и это норма для структуры адреса сокета Интернета. Почти все реализации добавляют элемент sin_zero, так что все структуры адреса сокета имеют размер как минимум 16 байт.
Типы элементов
s_addr
,
sin_family
и
sin_port
мы указываем согласно POSIX. Тип данных
in_addr_t
соответствует целому числу без знака длиной как минимум 32 бита,
in_port_t
— целому числу без знака длиной как минимум 16 бит, a
sa_family_t
— это произвольное целое число без знака. Последнее обычно представляет собой 8-разрядное целое без знака, если реализация поддерживает поле длины, либо 16-разрядное целое без знака, если поле длины не поддерживается. В табл. 3.1 перечислены эти три типа данных POSIX вместе с некоторыми другими типами данных POSIX, с которыми мы встретимся.
Таблица 3.1. Типы данных, требуемые POSIX
Тип данных | Описание | Заголовочный файл |
---|---|---|
int8_t | 8-разрядное целое со знаком | |
uint8_t | 8-разрядное целое без знака | |
int16_t | 16-разрядное целое со знаком | |
uint16_t | 16-разрядное целое без знака | |
int32_t | 32-разрядное целое со знаком | |
uint32_t | 32-разрядное целое без знака | |
sa_family_t | семейство адресов структуры адреса сокета | |
socklen_t | длина структуры адреса сокета, обычно типа uint32_t | |
in_addr_t | IPv4-адрес, обычно типа uint32_t | |
in_port_t | порт TCP или UDP, обычно типа uint16_t |
Вы также встретите типы данных
u_char
,
u_short
,
u_int
и
u_long
, которые не имеют знака. POSIX определяет их с замечанием, что они устарели. Они предоставляются в целях обратной совместимости.