KnigaRead.com/
KnigaRead.com » Компьютеры и Интернет » Программное обеспечение » Уильям Стивенс - UNIX: разработка сетевых приложений

Уильям Стивенс - UNIX: разработка сетевых приложений

На нашем сайте KnigaRead.com Вы можете абсолютно бесплатно читать книгу онлайн Уильям Стивенс, "UNIX: разработка сетевых приложений" бесплатно, без регистрации.
Перейти на страницу:

12.4. Макроопределения проверки адреса IPv6

Существует небольшой класс приложений IPv6, которые должны знать, с каким собеседником они взаимодействуют (IPv4 или IPv6). Эти приложения должны знать, является ли адрес собеседника адресом IPv4, преобразованным к виду IPv6. Определены двенадцать макросов, проверяющих некоторые свойства адреса Ipv6.

#include <netinet/in.h>


int IN6_IS_ADDR_UNSPECIFIED(const struct in6_addr *aptr);

int IN6_IS_ADDR_LOOPBACK(const struct in6_addr *aptr);

int IN6_IS_ADDR_MULTICAST(const struct in6_addr *aptr);

int IN6_IS_ADDR_LINKLOCAL(const struct in6_addr *aptr);

int IN6_IS_ADDR_SITELOCAL(const struct in6_addr *aptr);

int IN6_IS_ADDR_V4MAPPED(const struct in6_addr *aptr);

int IN6_IS_ADDR_V4COMPAT(const struct in6_addr *aptr);


int IN6_IS_ADDR_MC_NODELOCAL(const struct in6_addr *aptr);

int IN6_IS_ADDR_MC_LINKLOCAL(const struct in6_addr *aptr);

int IN6_IS_ADDR_MC_SITELOCAL(const struct in6_addr *aptr);

int IN6_IS_ADDR_MC_ORGLOCAL(const struct in6_addr *aptr);

int IN6_IS_ADDR_MC_GLOBAL(const struct in6_addr *aptr);

Все возвращают: ненулевое значение, если адрес IPv6 имеет указанный тип, 0 в противном случае

Первые семь макросов проверяют базовый тип адреса IPv6. Мы покажем различные типы адресов в разделе А.5. Последние пять макросов проверяют область действия адреса многоадресной передачи IPv6 (см. раздел 19.2).

Клиент IPv6 может вызвать макрос IN6_IS_ADDR_V4MAPPED для проверки адреса IPv6, возвращенного распознавателем. Сервер IPv6 может вызвать этот макрос для проверки адреса IPv6, возвращенного функцией accept или recvfrom.

Как пример приложения, которому нужен этот макрос, можно привести FTP и его команду PORT. Если мы запустим FTP-клиент, зарегистрируемся на FTP-сервере и выполним команду FTP dir, FTP-клиент пошлет команду PORT FTP-серверу через управляющее соединение. Она сообщит серверу IP-адрес и порт клиента, с которым затем сервер создаст соединение. (В главе 27 [111] содержатся подробные сведения о протоколе приложения FTP.) Но FTP-клиент IPv6 должен знать, с каким сервером имеет дело — IPv4 или IPv6, поскольку сервер IPv4 требует команду в формате PORT a1, a2, a3, a4, p1, p2 (где первые четыре числа, каждое от 0 до 255, формируют 4-байтовый адрес IPv4, а два последних — 2-байтовый номер порта), а серверу IPv6 необходима команда EPRT (RFC 2428 [3]), содержащая семейство адреса, адрес в текстовом формате и порт в текстовом формате. В упражнении 12.1 приводятся примеры использования обеих команд.

12.5. Переносимость исходного кода

Большинство существующих сетевых приложений написаны для IPv4. Структуры sockaddr_in размещаются в памяти и заполняются, а функция socket задает AF_INET в качестве первого аргумента. При переходе от листинга 1.1 к листингу 1.2 мы видели, что эти приложения IPv4 можно преобразовать в приложения IPv6 без особых усилий. Многие показанные нами изменения можно выполнить автоматически, используя некоторые сценарии редактирования. Программы, более зависящие от IPv4, использующие такие свойства, как многоадресная передача, параметры IP или символьные (неструктурированные) сокеты, потребуют больших усилий при преобразовании.

Если мы преобразуем приложение для работы с IPv6 и распространим его исходный код, нам придется думать о том, поддерживает ли принимающая система протокол IPv6. Типичный способ решения этой проблемы — применять в коде #ifdef, используя по возможности IPv6 (поскольку мы видели в этой главе, что клиент IPv6 может взаимодействовать с серверами IPv4 и наоборот). Проблема такого подхода в том, что код очень быстро засоряется директивами #ifdef, и его становится сложнее отслеживать и обслуживать.

Наилучшим подходом будет рассмотрение перехода на IPv6 как возможности сделать программу не зависящей от протокола. Первым шагом здесь будет удаление вызовов функций gethostbyname и gethostbyaddr и использование функций getaddrinfo и getnameinfo, описанных в предыдущей главе. Это позволит нам обращаться со структурами адресов сокетов как с непрозрачными объектами, ссылаться на которые можно с помощью указателя и размера, что как раз и выполняют основные функции сокетов: bind, connect, recvfrom и т.д. Наши функции sock_XXX из раздела 3.8 помогут работать с ними независимо от IPv4 и IPv6. Очевидно, эти функции содержат #ifdef для работы с IPv4 и IPv6, но если мы скроем эту зависимость от протокола в нескольких библиотечных функциях, наш код станет проще. В разделе 21.7 мы разработаем ряд функций mcast_XXX, которые помогут сделать приложения многоадресной передачи не зависящими от версии протокола IP.

Другой момент, который нужно учесть, — что произойдет, если мы откомпилируем наш исходный код в системе, поддерживающей и IPv4, и IPv6, затем распространим либо исполняемый код, либо объектные файлы (но не исходный код) и кто-то запустит наше приложение в системе, не поддерживающей IPv6. Есть вероятность, что сервер локальных имен поддерживает записи типа AAAA и возвращает как записи типа AAAA, так и записи типа А некоему собеседнику, с которым пытается соединиться наше приложение. Если наше приложение, работающее с IPv6, вызовет функцию socket для создания сокета IPv6, она не будет работать, если узел не поддерживает IPv6. Мы решаем этот вопрос с помощью функций, описанных в следующей главе, игнорируя ошибку функции socket и пытаясь использовать следующий адрес в списке, возвращаемом сервером имен. Если предположить, что у собеседника имеется запись типа А и что сервер имен возвращает запись типа А в дополнение к любой записи типа AAAA, то сокет IPv4 успешно создастся. Этот тип функциональности имеется в библиотечной функции, но не в исходном коде каждого приложения.

Чтобы получить возможность передавать дескрипторы сокетов, программам, работающим только с одним из протоколов, в стандарте RFC 2133 [37] предлагается использовать параметр сокета IPV6_ADDRFORM, позволяющий получить или изменить семейство сокета. Однако семантика параметра не была описана полностью, да и использоваться он мог только в очень специфических ситуациях, поэтому в следующей версии интерфейса сокетов данный параметр был отменен.

12.6. Резюме

Сервер IPv6 на узле с двойным стеком протоколов может предоставлять сервис как клиентам IPv4, так и клиентам IPv6. Клиент IPv4 посылает серверу дейтаграммы IPv4, но стек протоколов сервера преобразует адрес клиента к виду IPv6, поскольку сервер IPv6 работает со структурами адресов сокетов IPv6.

Аналогично, клиент IPv6 на узле с двойным стеком протоколов может взаимодействовать с сервером IPv4. Распознаватель клиента возвращает адреса IPv4, преобразованные к виду IPv6, для всех записей сервера типа А, и вызов функции connect для одного из этих адресов приводит к тому, что двойной стек посылает сегмент SYN IPv4. Только отдельным специальным клиентам и серверам необходимо знать протокол, используемый собеседником (например, FTP), и чтобы определить, что собеседник использует IPv4, можно использовать макрос IN6_IS_ADDR_V4MAPPED.

Упражнения

1. Запустите FTP-клиент IPv6 на узле с двойным стеком протоколов. Соединитесь с FTP-сервером IPv4, запустите команду debug, а затем команду dir. Далее выполните те же операции, но для сервера IPv6, и сравните команды PORT, являющиеся результатом выполнения команд dir.

2. Напишите программу, требующую ввода одного аргумента командной строки, который является адресом IPv4 в точечно-десятичной записи. Создайте TCP-сокет IPv4 и свяжите этот адрес и некоторый порт, например 8888, с сокетом при помощи функции bind. Вызовите функцию listen, а затем pause. Напишите аналогичную программу, которая в качестве аргумента командной строки принимает шестнадцатеричную строку IPv6 и создает прослушиваемый TCP-сокет IPv6. Запустите программу IPv4, задав в качестве аргумента универсальный адрес. Затем перейдите в другое окно и запустите программу IPv6, задав в качестве аргумента универсальный адрес IPv6. Можете ли вы запустить программу IPv6, если программа IPv4 уже связана с этим портом? Появляется ли разница при использовании параметра сокета SO_REUSEADDR? Что будет, если вы сначала запустите программу IPv6, а затем попытаетесь запустить программу IPv4?

Глава 13

Процессы-демоны и суперсервер inetd

13.1. Введение

Демон (daemon) — это процесс, выполняющийся в фоновом режиме и не связанный с управляющим терминалом. Системы Unix обычно имеют множество процессов (от 20 до 50), которые являются демонами, работают в фоновом режиме и выполняют различные административные задачи.

Независимость от терминала обычно является побочным эффектом запуска из системного сценария инициализации (например, в процессе загрузки компьютера). Если же демон запускается командой интерпретатора, он должен самостоятельно отключиться от терминала во избежание нежелательного взаимодействия с системами управления задачами, сеансами терминалов, а также вывода на терминал при работе в фоновом режиме.

Перейти на страницу:
Прокомментировать
Подтвердите что вы не робот:*