UNIX: разработка сетевых приложений
■ Элемент
разделен на три поля:sin6_flowinfo□ 20 бит младшего порядка — это метка потока;
□ следующие 12 бит зарезервированы.
Поле метки потока и поле приоритета рассматриваются в описании рис. А.2. Отметим, что использование поля приоритета еще не определено.
■ Элемент
определяет контекст, в котором действует контекстный адрес (scoped address). Чаще всего это бывает индекс интерфейса для локальных адресов (см. раздел А.5).sin6_scope_idНовая универсальная структура адреса сокета
Новая универсальная структура адреса сокета была определена как часть API сокетов IPv6 с целью преодолеть некоторые недостатки существующей структуры
. В отличие от структурыsockaddr, новая структураsockaddrдостаточно велика для хранения адреса сокета любого типа, поддерживаемого системой. Новая структура задается подключением заголовочного файлаsockaddr_storage, часть которого показана в листинге 3.4.<netinet/in.h>Листинг 3.4. Структура хранения адреса сокета sockaddr_storage
struct sockaddr_storage {uint8_t ss_len; /* длина этой структуры (зависит от реализации) */sa_family_t ss_family; /* семейство адреса. AF_xxx *//* зависящие от реализации элементы, обеспечивающие:а) выравнивание, достаточное для выполнения требований по выравниванию всехтипов адресов сокетов, поддерживаемых системой;б) достаточный объем для хранения адреса сокета любого типа,поддерживаемого системой. */};Тип
— это универсальная структура адреса сокета, отличающаяся отsockaddr_storageпо следующим параметрам:struct sockaddr1. Если к структурам адресов сокетов, поддерживаемым системой, предъявляются требования по выравниванию, структура
выполняет самое жесткое из них.sockaddr_storage2. Структура
достаточно велика для размещения любой структуры адреса сокета, поддерживаемой системой.sockaddr_storageЗаметьте, что поля структуры
непрозрачны для пользователя, за исключениемsockaddr_storageиss_family(если таковые заданы). Структураss_lenдолжна преобразовываться в структуру адреса соответствующего типа для обращения к содержимому остальных полей.sockaddr_storageСравнение структур адреса сокетов
На рис. 3.1 показано сравнение пяти структур адресов сокетов, с которыми мы встретимся в тексте, предназначенных для IPv4, IPv6, доменного сокета Unix (см. листинг 15.1), канального уровня (см. листинг 18.1) и хранения. Подразумевается, что все структуры адреса сокета содержат 1-байтовое поле длины, поле семейства также занимает 1 байт и длина любого поля, размер которого ограничен снизу, в точности равна этому ограничению.
Рис. 3.1. Сравнение различных структур адресов сокетов
Две структуры адреса сокета имеют фиксированную длину, а структура доменного сокета Unix и структура канального уровня — переменную. При обработке структур переменной длины мы передаем функциям сокетов указатель на структуру адреса сокета, а в другом аргументе передаем длину этой структуры. Под каждой структурой фиксированной длины мы показываем ее размер в байтах (для реализации 4.4BSD).
ПРИМЕЧАНИЕСама структура sockaddr_un имеет фиксированную длину, но объем информации в ней — длина полного имени (pathname) — может быть переменным. Передавая указатели на эти структуры, следует соблюдать аккуратность при обработке поля длины — как длины в структуре адреса сокета (если поле длины поддерживается данной реализацией), так и длины данных, передаваемых ядру и принимаемых от него.
Этот рисунок служит также иллюстрацией стиля, которого мы придерживаемся в этой книге: названия структур на рисунках всегда выделяются полужирным шрифтом, а за ними следуют фигурные скобки.
Ранее отмечалось, что в реализации 4.3BSD Reno ко всем структурам адресов сокетов было добавлено поле длины. Если бы поле длины присутствовало в оригинальной реализации сокетов, то не возникло бы необходимости передавать аргумент длины функциям сокетов (третий аргумент функций bind и connect). Вместо этого размер структуры мог бы храниться в поле длины структуры.
3.3. Аргументы типа «значение-результат»
Мы отмечали, что когда структура адреса сокета передается какой-либо из функций сокетов, она всегда передается по ссылке, то есть в качестве аргумента передается указатель на структуру. Длина структуры также передается в качестве аргумента. Но способ, которым передается длина, зависит от того, в каком направлении передается структура: от процесса к ядру или наоборот.
1. Три функции
,bindиconnectпередают структуру адреса сокета от процесса к ядру. Один из аргументов этих функций — указатель на структуру адреса сокета, другой аргумент — это целочисленный размер структуры, как показано в следующем примере:sendtostruct sockaddr_in serv;/* заполняем serv{} */connect(sockfd, (SA*)&serv, sizeof(serv));Поскольку ядру передается и указатель, и размер структуры, на которую он указывает, становится точно известно, какое количество данных нужно скопировать из процесса в ядро. На рис. 3.2 показан этот сценарий.
Рис. 3.2. Структура адреса сокета, передаваемая от процесса к ядру
В следующей главе мы увидим, что размер структуры адреса сокета в действительности имеет тип
, а неsocklen_t, но POSIX рекомендует определятьint_t какsocklen.uint32_t2. Четыре функции
,accept,recvfromиgetsocknameпередают структуру адреса сокета от ядра к процессу, то есть в направлении, противоположном предыдущему случаю. Этим функциям передается указатель на структуру адреса сокета и указатель на целое число, содержащее размер структуры, как показано в следующем примере:getpeernamestruct sockaddr_un cli; /* домен Unix */socklen_t len;len = sizeof(cli); /* len - это значение */getpeername(unixfd, (SA*)&cli, &len);/* значение len могло измениться */

