UNIX: разработка сетевых приложений
Шрифт:
Часть 2
Элементарные сокеты
Глава 3
Введение в сокеты
3.1. Введение
Эта глава начинается с описания программного интерфейса приложения (API) сокетов. Мы начнем со структур адресов сокетов, которые будут встречаться почти в каждом примере на протяжении всей книги. Эти структуры можно передавать в двух направлениях: от процесса к ядру и от ядра к процессу. Последний случай — пример аргумента, через который передается возвращаемое значение, и далее в книге мы встретимся с другими примерами таких аргументов.
Перевод текстового представления адреса в двоичное значение, входящее в структуру адреса сокета, осуществляется функциями преобразования адресов. В большей части существующего кода IPv4 используются функции
Одной из проблем этих функций является то, что они зависят от протокола, так как для них имеет значение тип преобразуемого адреса — IPv4 или IPv6. Мы разработали набор функций, названия которых начинаются с
3.2. Структуры адреса сокетов
Большинство функций сокетов используют в качестве аргумента указатель на структуру адреса сокета. Каждый набор протоколов определяет свою собственную структуру адреса сокетов. Имена этих структур начинаются с
Структура адреса сокета IPv4
Структура адреса сокета IPv4, обычно называемая структурой адреса сокета Интернета, именуется
1
Все исходные коды программ, опубликованные в этой книге, вы можете найти по адресу http://www.piter.com.
Листинг 3.1. Структура адреса сокета Интернета (IPv4): sockaddr_in
Есть несколько моментов, касающихся структур адреса сокета в целом, которые мы покажем на примере.
Элемент длины
Даже если поле длины присутствует, нам не придется устанавливать и проверять его значение, пока мы не имеем дела с маршрутизирующими сокетами (см. главу 18). Оно используется внутри ядра процедурами, работающими со структурами адресов сокетов из различных семейств протоколов (например, код таблицы маршрутизации).
Четыре функции, передающие структуру адреса сокета от процесса к ядру, — 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 требует наличия только трех элементов структуры:
Типы элементов
Таблица 3.1. Типы данных, требуемые POSIX
Тип данных | Описание | Заголовочный файл |
---|---|---|
int8_t | 8-разрядное целое со знаком | <sys/types.h> |
uint8_t | 8-разрядное целое без знака | <sys/types.h> |
int16_t | 16-разрядное целое со знаком | <sys/types.h> |
uint16_t | 16-разрядное целое без знака | <sys/types.h> |
int32_t | 32-разрядное целое со знаком | <sys/types.h> |
uint32_t | 32-разрядное целое без знака | <sys/types.h> |
sa_family_t | семейство адресов структуры адреса сокета | <sys/socket.h> |
socklen_t | длина структуры адреса сокета, обычно типа uint32_t | <sys/socket.h> |
in_addr_t | IPv4-адрес, обычно типа uint32_t | <netinet/in.h> |
in_port_t | порт TCP или UDP, обычно типа uint16_t | <netinet/in.h> |
Вы также встретите типы данных
И адрес IPv4, и номер порта TCP и UDP всегда хранятся в структуре в соответствии с порядком байтов, определенным в сети ( сетевой порядок байтов— network byte order). Об этом нужно помнить при использовании этих элементов (более подробно о разнице между порядком байтов узла и порядком байтов в сети мы поговорим в разделе 3.4).
К 32-разрядному адресу IPv4 можно обратиться двумя путями. Например, если