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

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

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

2. Устраните проблему, показанную в предыдущем упражнении.

3. Запустите программу, показанную в листинге 11.4, задав имя службы chargen.

4. Запустите программу, показанную в листинге 11.4, задав IP-адрес в точечно- десятичной записи в качестве имени узла. Допускает ли это ваш распознаватель? Измените листинг 11.4, чтобы разрешить IP-адрес в виде строки десятичных чисел с точками в качестве имени узла и строку с десятичным номером порта в качестве имени службы. В каком порядке должно выполняться тестирование IP-адреса для строки в точечно-десятичной записи и для имени?

5. Измените программу в листинге 11.4 так, чтобы можно было работать либо с IPv4, либо с IPv6.

6. Измените программу в листинге 8.5 так, чтобы сделать запрос DNS, и сравните возвращаемый IP-адрес со всеми IP-адресами узла получателя, то есть вызовите функцию gethostbyaddr, используя IP-адрес, возвращаемый функцией recvfrom, а затем вызовите gethostbyname для поиска всех IP-адресов для узла.

7. Измените листинг 11.6, чтобы вызвать функцию getnameinfo вместо функции sock_ntop. Какие флаги вы должны передать функции getnameinfo?

8. В разделе 7.5 мы обсуждали завладение портом с помощью параметра сокета SO_REUSEADDR. Чтобы увидеть, как это происходит, создайте не зависящий от протокола сервер времени и даты UDP, показанный в листинге 11.13. Запустите один экземпляр сервера в одном окне, свяжите его с универсальным адресом и некоторым портом, который вы выберете. Запустите в другом окне клиент и убедитесь, что этот сервер выполняет обработку клиента (отметьте вызов функции printf на узле сервера). Затем запустите другой экземпляр сервера в другом окне, и на этот раз свяжите его с одним из адресов направленной передачи узла и тем же портом, что и первый сервер. С какой проблемой вы сразу же столкнетесь? Устраните эту проблему и перезапустите второй сервер. Запустите клиент, отправьте дейтаграмму и проверьте, что второй сервер захватил порт первого сервера. Если возможно, запустите второй сервер снова с учетной записью, отличной от учетной записи первого сервера, чтобы проверить, происходит ли по-прежнему захват порта, поскольку некоторые производители не допускают второго связывания, если идентификатор пользователя отличен от идентификатора процесса, уже связанного с портом.

9. В конце раздела 2.12 мы показали два примера Telnet: сервер времени и даты и эхо-сервер. Зная, что клиент проходит через два этапа — функцию gethostbyname и функцию connect, определите, к каким этапам относятся строки вывода клиента.

10. Функции getnameinfo может потребоваться длительное время (до 80 с) на возвращение ошибки, если для IP-адреса не может быть найдено имя узла. Напишите новую функцию getnameinfo_timeo, которая получает дополнительный целочисленный аргумент, задающий максимальную длительность ожидания ответа в секундах. Если время таймера истекает и флаг NI_NAMEREQD не задан, вызовите функцию inet_ntop и возвратите строку адреса.

Часть 3

Дополнительные возможности сокетов

Глава 12

Совместимость IPv4 и IPv6

12.1. Введение

В течение ближайших лет, возможно, произойдет постепенный переход Интернета с IPv4 на IPv6. Во время этого переходного периода важно, чтобы существующие приложения IPv4 продолжали работать с более новыми приложениями IPv6. Например, производитель не может предложить клиент Telnet, работающий только с серверами IPv6, — он должен предоставить и клиент для серверов IPv4, и клиент для серверов IPv6. Мы бы предпочли обойтись одним Telnet-клиентом IPv6, способным работать с серверами и IPv4, и IPv6, и одним сервером Telnet, который работал бы с клиентами и IPv4, и IPv6. В этой главе мы увидим, как это сделать.

В этой главе мы предполагаем, что на узлах работают двойные стеки протоколов (dual stacks), то есть набор протоколов IPv4 и набор протоколов IPv6. На рис. 2.1 представлен узел с двойным стеком. Возможно, узлы и маршрутизаторы будут работать подобным образом в течение многих лет в процессе перехода к IPv6. В какой-то момент многие системы смогут отключить свои стеки IPv4, но только с течением времени можно будет сказать, когда это произойдет, да и произойдет ли вообще.

В этой главе мы обсудим, каким образом приложения IPv4 и IPv6 могут взаимодействовать друг с другом. Существует четыре комбинации клиентов и серверов, использующих либо IPv4, либо IPv6, что показано в табл. 12.1.


Таблица 12.1. Сочетания клиентов и серверов, использующих IPv4 или IPv6

Сервер IPv4 Сервер IPv6 Клиент IPv4 и серверы Почти все существующие клиенты Обсуждается в разделе 12.2 Клиент IPv6 Обсуждается в разделе 12.3 Простые модификации большинства существующих клиентов (например, клиент из листинга 1.1 модифицируется к виду, представленному в листинге 1.2)

Мы не будем подробно рассматривать два сценария, когда клиент и сервер используют один и тот же протокол. Более интересны случаи, когда клиент и сервер используют разные протоколы.

12.2. Клиент IPv4, сервер IPv6

Общим свойством узла с двойным стеком является то, что серверы IPv6 могут выполнять обслуживание клиентов IPv4 и IPv6. Это достигается за счет преобразования адресов IPv4 к виду IPv6 (см. рис. А.6). Пример такого преобразования приведен на рис. 12.1.

Рис. 12.1. Сервер IPv6 на узле с двойным стеком, обслуживающий клиенты IPv4 и IPv6

Слева у нас находятся клиент IPv4 и клиент IPv6. Сервер (справа) написан с использованием IPv6 и запущен на узле с двойным стеком. Сервер создал прослушиваемый TCP-сокет IPv6, связанный с универсальным адресом IPv6, и порт TCP 9999.

Мы считаем, что клиент и сервер находятся в одной сети Ethernet. Они могут быть соединены и через маршрутизаторы, поскольку все маршрутизаторы поддерживают и IPv4, и IPv6, но в данном случае это ничего не меняет. В разделе Б.3 описывается другой случай, когда клиенты и серверы IPv6 соединяются через маршрутизаторы, поддерживающие только IPv4.

Мы считаем, что оба клиента посылают сегменты SYN для установления соединения с сервером. Узел клиента IPv4 посылает сегмент SYN и дейтаграмму IPv4, а клиент IPv6 посылает сегмент SYN и дейтаграмму IPv6. Сегмент TCP от клиента IPv4 выглядит в сети как заголовок Ethernet, за которым идет заголовок IPv4, заголовок TCP и данные TCP. Заголовок Ethernet содержит поле типа 0x0800, которое идентифицирует кадр как кадр IPv4. Заголовок TCP содержит порт получателя 9999 (в приложении А рассказывается более подробно о форматах и содержании этих заголовков). IP-адрес получателя в заголовке IPv4, который мы не показываем, — это 206.62.226.42.

Сегмент TCP от клиента IPv6 выглядит в сети как заголовок Ethernet, за которым следует заголовок IPv6, заголовок TCP и данные TCP. Заголовок Ethernet содержит поле типа 0x86dd, которое идентифицирует кадр как кадр IPv6. Заголовок TCP имеет тот же формат, что и заголовок TCP в пакете IPv4, и содержит порт получателя 9999. IP-адрес получателя в заголовке IPv6, который мы не показываем, будет таким: 5f1b:df00:ce3e:e200:20:800:2b37:6426.

Принимающий канальный уровень просматривает поле типа Ethernet и передает каждый кадр соответствующему модулю IP. Модуль IPv4 (возможно, вместе с модулем TCP) определяет, что сокетом получателя является сокет IPv6, и IPv4-адрес отправителя в заголовке IPv4 заменяется на эквивалентный ему адрес IPv4, преобразованный к виду IPv6. Этот преобразованный адрес возвращается сокету IPv6 как IPv6-адрес клиента, когда функция accept сервера соединяется с клиентом IPv4. Все оставшиеся дейтаграммы для этого соединения являются дейтаграммами IPv4.

Когда функция сервера accept соединяется с клиентом IPv6, клиентский адрес IPv6 остается таким же, каким был адрес отправителя в заголовке IPv6. Все оставшиеся дейтаграммы для этого соединения являются дейтаграммами IPv6.

Теперь мы можем свести воедино шаги, позволяющие TCP-клиенту IPv4 соединяться с сервером IPv6.

1. Сервер IPv6 запускается, создает прослушиваемый сокет IPv6, и мы считаем, что с помощью функции bind он связывает с сокетом универсальный адрес.

2. Клиент IPv4 вызывает функцию gethostbyname и находит запись типа А для сервера. У узла сервера будут записи и типа А, и типа AAAA, поскольку он поддерживает оба протокола, но клиент IPv4 запрашивает только запись типа А.

3. Клиент вызывает функцию connect, и клиентский узел отправляет серверу сегмент SYN IPv4.

4. Узел сервера получает сегмент SYN IPv4, направленный прослушиваемому сокету IPv6, устанавливает флаг, указывающий, что это соединение использует адреса IPv4, преобразованные к виду IPv6, и отвечает сегментом IPv4 SYN/ACK. Когда соединение установлено, адрес, возвращаемый серверу функцией accept, является адресом IPv4, преобразованным к виду IPv6.

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