В табл. 8.2 сводятся воедино свойства, перечисленные в первом пункте, применительно к 4.4BSD.
Таблица 8.2. Сокеты TCP и UDP: может ли быть задан адрес протокола получателя
Тип сокета |
write или send |
sendto, без указания получателя |
sendto, с указанием получателя |
Сокет TCP |
Да |
Да |
EISCONN |
Сокет UDP, присоединенный |
Да |
Да |
EISCONN |
Сокет UDP, неприсоединенный |
EDESTADDRREQ |
EDESTADDRREQ |
Да |
ПРИМЕЧАНИЕ
POSIX определяет, что операция вывода, не задающая адрес получателя на неприсоединенном сокете UDP, должна возвращать ошибку ENOTCONN, а не EDESTADDRREQ.
Solaris 2.5 допускает функцию sendto, которая задает адрес получателя для присоединенного сокета UDP. POSIX определяет, что в такой ситуации должна возвращаться ошибка EISCONN.
На рис. 8.7 обобщается информация о присоединенном сокете UDP.
Рис. 8.7. Присоединенный сокет UDP
Приложение вызывает функцию 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
для последовательной отправки двух дейтаграмм на неприсоединенном сокете включает следующие шесть шагов, выполняемых ядром:
Читать дальше
Конец ознакомительного отрывка
Купить книгу