UNIX: разработка сетевых приложений
3. Один из способов определить, какие узлы в вашей подсети имеют возможность многоадресной передачи, заключается в запуске утилиты
для группы всех узлов, то есть для адреса 224.0.0.1. Попробуйте это сделать.ping4. Одним из способов обнаружения маршрутизаторов многоадресной передачи в вашей подсети является запуск утилиты ping для группы всех маршрутизаторов — 224.0.0.2. Попробуйте это сделать.
5. Один из способов узнать, соединен ли ваш узел с многоадресной IP-инфраструктурой — запустить нашу программу из раздела 21.9, подождать несколько минут и посмотреть, появляются ли анонсы сеанса. Попробуйте сделать это и посмотрите, получите ли вы какие-нибудь анонсы.
6. Выполните вычисления в листинге 21.12 при условии, что дробная часть отметки времени NTP равна 1 073 741 824 (одна четвертая от 232).
Выполните еще раз эти же вычисления для максимально возможной дробной части (232 - 1).
Измените реализацию функции
для IPv4 так, чтобы запоминать имя каждого интерфейса, для которого она получает IP-адрес. Это позволит избежать нового вызова функцииmcast_set_ifдля данного интерфейса.ioctlГлава 22
Дополнительные сведения о сокетах udp
22.1. Введение
Эта глава объединяет различные темы, касающиеся приложений, использующих сокеты UDP. Для начала нас интересует, как определяется адрес получателя дейтаграммы UDP и интерфейс, на котором дейтаграмма была получена, поскольку сокет, связанный с портом UDP и универсальным адресом, может получать дейтаграммы направленной, широковещательной и многоадресной передачи на любом интерфейсе.
TCP — это потоковый протокол, использующий окно переменной величины (sliding window), поэтому в TCP отсутствует такое понятие, как граница записи, и невозможно переполнение буфера получателя отправителем в результате передачи слишком большого количества данных. Однако в случае UDP каждой операции ввода соответствует одна дейтаграмма UDP (запись), поэтому возникает вопрос: что произойдет, когда полученная дейтаграмма окажется больше приемного буфера приложения?
UDP — это ненадежный протокол, однако существуют приложения, в которых UDP использовать целесообразнее, чем TCP. Мы рассмотрим факторы, под влиянием которых UDP оказывается предпочтительнее TCP. В UDP-приложения необходимо включать ряд функций, в некоторой степени компенсирующих ненадежность UDP: тайм-аут и повторную передачу, обработку потерянных дейтаграмм и порядковые номера для сопоставления ответов запросам. Мы разработаем набор функций, которые сможем вызывать из наших приложений UDP.
Если реализация не поддерживает параметр сокета
, один из способов определить IP-адрес получателя UDP-дейтаграммы заключается в связывании всех интерфейсных адресов и использовании функцииIP_RECVDSTADDR.selectБольшинство серверов UDP являются последовательными, но существуют приложения, обменивающиеся множеством дейтаграмм UDP между клиентом и сервером, что требует параллельной обработки. Примером может служить TFTP (Trivial File Transfer Protocol — упрощенный протокол передачи файлов). Мы рассмотрим два варианта подобного согласования — с использованием суперсервера
и без него.inetdВ завершение этой главы мы рассмотрим информацию о пакете, которая может быть передана во вспомогательных данных дейтаграммы IPv6: IP-адрес отправителя, отправляющий интерфейс, предельное количество транзитных узлов исходящих дейтаграмм и адрес следующего транзитного узла. Аналогичная информация — IP-адрес получателя, принимающий интерфейс и предельное количество транзитных узлов — может быть получена вместе с дейтаграммой IPv6.
22.2. Получение флагов, IP-адреса получателя и индекса интерфейса
Исторически функции
иsendmsgиспользовались только для передачи дескрипторов через доменные сокеты Unix (см. раздел 15.7), но даже это происходило сравнительно редко. Однако в настоящее время популярность этих двух функций растет по двум причинам:recvmsg1. Элемент
, добавленный в структуруmsg_flagsв реализации 4.3BSD Reno, возвращает приложению флаги сообщения. Эти флаги мы перечислили в табл. 14.2.msghdr2. Вспомогательные данные используются для передачи все большего количества информации между приложением и ядром. В главе 27 мы увидим, что IPv6 продолжает эту тенденцию.
В качестве примера использования функции
мы напишем функциюrecvmsg, аналогичную функции recvfrom, но дополнительно позволяющую получить:recvfrom_flags■ возвращаемое значение
;msg_flags■ адрес получателя полученной дейтаграммы (из параметра сокета
);IP_RECVDSTADDR■ индекс интерфейса, на котором была получена дейтаграмма (параметр сокета
).IP_RECVIFЧтобы можно было получить два последних элемента, мы определяем в нашем заголовке
следующую структуру:unp.hstruct in_pktinfo {struct in_addr ipi_addr; /* IPv4-адрес получателя */int ipi_ifindex; /* индекс интерфейса, на котором былаполучена дейтаграмма */};Мы выбрали имена структуры и ее элементов так, чтобы получить определенное сходство со структурой IPv6
, возвращающей те же два элемента для сокета IPv6 (см. раздел 22.8). Наша функцияin6_pktinfoбудет получать в качестве аргумента указатель на структуруrecvfrom_flags, и если этот указатель не нулевой, возвращать структуру через указатель.in_pktinfoПроблема построения этой структуры состоит в том, что неясно, что возвращать, если недоступна информация, которая должна быть получена из параметра сокета
(то есть реализация не поддерживает данный параметр сокета). Обработать индекс интерфейса легко, поскольку нулевое значение может использоваться как указание на то, что индекс неизвестен. Но для IP-адреса все 32-разрядные значения являются действительными. Мы выбрали такое решение: адрес получателя 0.0.0.0 возвращается в том случае, когда действительное значение недоступно. Хотя это реальный IP-адрес, использовать его в качестве IP-адреса получателя не разрешается (RFC 1122 [10]). Он будет действителен только в качестве IP-адреса отправителя во время начальной загрузки узла, когда узел еще не знает своего IP-адреса.IP_RECVDSTADDRПРИМЕЧАНИЕК сожалению, Беркли-ядра принимают дейтаграммы, предназначенные для адреса 0.0.0.0 [128, с. 218-219]. Это устаревшие адреса широковещательной передачи, генерируемые ядрами 4.2BSD.
Первая часть нашей функции
представлена в листинге 22.1 [1]. Эта функция предназначена для использования с сокетом UDP.recvfrom_flagsЛистинг 22.1. Функция recvfrom_flags: вызов функции recvmsg
//adviо/recvfromflags.c