int bind(int, struct sockaddr*, socklen_t);
При этом требуется, чтобы для любых вызовов этих функций указатель на структуру адреса сокета, специфичную для протокола, был преобразован в указатель на универсальную структуру адреса сокета. Например:
struct sockaddr_in serv; /* структура адреса сокета IPv4 */
/* заполняем serv{} */
bind(sockfd, (struct sockaddr*)&serv, sizeof(serv));
Если мы не выполним преобразование (
struct sockaddr*
), компилятор С сгенерирует предупреждение в форме
"Warning: passing arg 2 of 'bind' from incompatible pointer type"
(Передается указатель несовместимого типа). Здесь мы предполагаем, что в системных заголовочных файлах имеется прототип ANSI С для функции bind.
С точки зрения разработчика приложений, универсальная структура адреса сокета используется только для преобразования указателей на структуры адресов конкретных протоколов.
Вспомните, что в нашем заголовочном файле unp.h (см. раздел 1.2) мы определили SA как строку "struct sockaddr", чтобы сократить код, который мы написали для преобразования этих указателей.
С точки зрения ядра основанием использовать в качестве аргументов указатели на универсальные структуры адреса сокетов является то, что ядро должно получать указатель вызывающей функции, преобразовывать его в struct sockaddr, а затем по значению элемента sa_family определять тип структуры. Но разработчику приложений было бы проще работать с указателем void*, поскольку это избавило бы его от необходимости выполнять явное преобразование указателя.
Структура адреса сокета IPv6
Структура адреса сокета IPv6 задается при помощи включения заголовочного файла
, как показано в листинге 3.3.
Листинг 3.3. Структура адреса сокета IPv6: sockaddr_in6
struct in6_addr {
uint8_t s6_addr[16]; /* 128-разрядный адрес IPv6 */
/* сетевой порядок байтов */
};
#define SIN6_LEN /* требуется для проверки во время компиляции */
struct sockaddr_in6 {
uint8_t sin_len; /* длина этой структуры (24) */
sa_family_t sin6_family; /* AF_INET6 */
in_port_t sin6_port; /* номер порта транспортного уровня */
/* сетевой порядок байтов */
uint32_t sin6_flowinfo; /* приоритет и метка потока */
/* сетевой порядок байтов */
struct in6_addr sin6_addr; /* IPv6-адрес */
/* сетевой порядок байтов */
uint32_t sin6_scope_id; /* набор интерфейсов */
};
Расширения API сокетов для IPv6 описаны в RFC 3493 [36].
Отметим следующие моменты относительно листинга 3.3:
Константа
SIN6_LEN
должна быть задана, если система поддерживает поле длины для структур адреса сокета.
Семейством IPv6 является
AF_INET6
, в то время как семейство IPv4 —
AF_INET
.
Элементы в структуре упорядочены таким образом, что если структура
sockaddr_in6
выровнена по 64 битам, то так же выровнен и 128-разрядный элемент
sin6_addr
. На некоторых 64-разрядных процессорах доступ к данным с 64-разрядными значениями оптимизирован, если данные выровнены так, что их адрес кратен 64.
Элемент
sin6_flowinfo
разделен на три поля:
20 бит младшего порядка — это метка потока;
следующие 12 бит зарезервированы.
Поле метки потока и поле приоритета рассматриваются в описании рис. А.2. Отметим, что использование поля приоритета еще не определено.
Элемент
sin6_scope_id
определяет контекст, в котором действует контекстный адрес (scoped address). Чаще всего это бывает индекс интерфейса для локальных адресов (см. раздел А.5).