Приложение вызывает функцию
connect
, задавая IP-адрес и номер порта собеседника. Затем оно использует функции
read
и
write
для обмена данными с собеседником.Дейтаграммы, приходящие с любого другого IP-адреса или порта (который мы обозначаем как «???» на рис. 8.7), не передаются на присоединенный сокет, поскольку либо IP-адрес, либо UDP-порт отправителя не совпадают с адресом протокола, с которым сокет соединяется с помощью функции
connect
. Эти дейтаграммы могут быть доставлены на какой-то другой сокет UDP на узле. Если нет другого совпадающего сокета для приходящей дейтаграммы, UDP проигнорирует ее и сгенерирует ICMP-сообщение о недоступности порта.Обобщая вышесказанное, мы можем утверждать, что клиент или сервер UDP может вызвать функцию
connect
, только если этот процесс использует сокет UDP для связи лишь с одним собеседником. Обычно именно клиент UDP вызывает функцию
connect
, но существуют приложения, в которых сервер UDP связывается с одним клиентом на длительное время (например, TFTP), и в этом случае и клиент, и сервер вызывают функцию
connect
.Еще один пример долгосрочного взаимодействия — это DNS (рис. 8.8).
Рис. 8.8
. Пример клиентов и серверов DNS и функции connectКлиент DNS может быть сконфигурирован для использования одного или более серверов, обычно с помощью перечисления IP-адресов серверов в файле
/etc/resolv.conf
. Если в этом файле указан только один сервер (на рисунке этот клиент изображен в крайнем слева прямоугольнике), клиент может вызвать функцию connect, но если перечислено множество серверов (второй справа прямоугольник на рисунке), клиент не может вызвать функцию
connect
. Обычно сервер DNS обрабатывает также любые клиентские запросы, следовательно, серверы не могут вызывать функцию
connect
.Многократный вызов функции connect для сокета UDP
Процесс с присоединенным сокетом UDP может снова вызвать функцию
connect
Для этого сокета, чтобы:задать новый IP-адрес и порт;
отсоединить сокет.
Первый случай, задание нового собеседника для присоединенного сокета UDP, отличается от использования функции
connect
с сокетом TCP: для сокета TCP функция
connect
может быть вызвана только один раз.Чтобы отсоединить сокет UDP, мы вызываем функцию
connect
, но присваиваем элементу семейства структуры адреса сокета (
sin_family
для IPv4 или
sin6_family
для IPv6) значение
AF_UNSPEC
. Это может привести к ошибке
EAFNOSUPPORT
[128, с. 736], но это нормально. Именно процесс вызова функции
connect
на уже присоединенном сокете UDP позволяет отсоединить сокет [128, с. 787–788].В руководстве BSD по поводу функции connect традиционно говорилось: «Сокеты дейтаграмм могут разрывать связь, соединяясь с недействительными адресами, такими как пустые адреса». К сожалению, ни в одном руководстве не сказано, что представляет собой «пустой адрес», и не упоминается, что в результате возвращается ошибка (что нормально). Стандарт POSIX явно указывает, что семейство адресов должно быть установлено в AF_UNSPEC, но затем сообщает, что этот вызов функции connect может возвратить, а может и не возвратить ошибку EAFNOSUPPORT.
Производительность
Когда приложение вызывает функцию
sendto
на неприсоединенном сокете UDP, ядра реализаций, происходящих от Беркли, временно соединяются с сокетом, отправляют дейтаграмму и затем отсоединяются от сокета [128, с. 762–763]. Таким образом, вызов функции
sendto
для последовательной отправки двух дейтаграмм на неприсоединенном сокете включает следующие шесть шагов, выполняемых ядром:присоединение сокета;
вывод первой дейтаграммы;
отсоединение сокета;
присоединение сокета;
вывод второй дейтаграммы;
отсоединение сокета.