• Протоколы без соединений обрабатывают перезапуски машин более плавно, поскольку нет необходимости в переустановке соединений. Это очень заманчивое свойство для сетевых файловых систем (таких как NFS, действующей на основе UDP), поскольку оно позволяет перезапускать файловый сервер без уведомления клиента.
• Простейшие протоколы могут работать гораздо быстрее через дейтаграммный протокол. Служба имен доменов DNS использует UDP только по этой причине (несмотря на то что наряду с этим дополнительно поддерживается TCP). При установке соединения TCP клиентская машина отправляет сообщение на сервер, получает от сервера подтверждение, указывающее на активность соединения, затем сообщает серверу о том, что установлена клиентская сторона соединения [137] Это называется трехсторонним квитированием TCP, которое на самом деле проходит несколько сложнее, чем описано выше.
23. После этого клиент может отправить свой запрос имени хоста на взаимодействующий сервер. Все это в итоге составляет процесс из пяти сообщений, не считая проверки ошибок и ожидания фактического отправления запроса и ответа на него. Используя UDP, запросы имени хоста пересылаются как первый пакет на сервер, который отвечает одним или более UDP-пакетами, тем самым уменьшая общий счетчик пакетов до пяти. Если клиент не получает ответ, то он просто перепосылает запрос.
• При первичной установке компьютеров часто требуется установить для них IP-адрес, а затем загрузить первую часть операционной системы через сеть [138] Этот процесс называется сетевой загрузкой.
. Применение UDP для подобных операций создает набор протоколов, который внедряется в такие машины гораздо проще, чем, если бы требовалась полная TCP-реализация.
17.6.1. Создание UDP-сокета
Как и любой другой сокет, UDP-сокет создается с помощью функции socket()
, однако второй аргумент должен быть SOCK_DGRAM
, а последний — либо IPPROTO_UDP
, либо просто ноль (так как UDP является стандартным IP-дейтаграммным протоколом).
После создания сокета ему необходимо присвоить номер локального порта. Это происходит тогда, когда программа удовлетворяет одному из следующих трех условий.
• Номер порта задается явно через вызов функции bind(). Этот шаг является обязательным для тех серверов, для которых необходимо получение дейтаграмм на номер официального порта. Системный вызов в точности совпадает с системным вызовом для TCP-серверов.
• Дейтаграмма посылается через сокет. Ядро присваивает данному сокету номер порта UDP при первой передаче данных через него. В большинстве клиентских программ применяется именно этот прием, поскольку номер используемого порта для них не имеет значения.
• Для сокета устанавливается удаленный адрес через функцию connect()
(которая является дополнительной для UDP-сокетов).
Также существует два различных способа присвоения номера удаленного порта. Вспомните о том, что TCP-сокеты имеют удаленный адрес, который присваивается через connect()
. Этот адрес может использоваться и для UDP-сокетов [139] UDP-сокеты, которые имеют постоянные пункты назначения, присвоенные через функцию connect() , иногда называются присоединенными UDP-сокетами.
. При этом функция connect()
для TCP вызывает обмен пакетами для инициализации соединения (что делает connect()
медленным системным вызовом), в то время как вызов connect()
для UDP-сокетов просто присваивает удаленный IP-адрес и номер порта для исходящих дейтаграмм (и является быстрым системным вызовом). Еще одно различие состоит в том, что приложения могут подключаться к TCP-сокету только один раз; UDP-сокеты могут повторно использовать свои адреса назначения [140] Есть также возможность превратить подключенный сокет в неподключенный с помощью функции connect() , однако эта процедура не стандартизирована. Если вам все же необходимо ее применить, обратитесь к [33].
.
Преимущество использования подключенных UDP-сокетов состоит в том, что только та машина и порт, которые указаны как удаленный адрес для сокета, могут передавать дейтаграммы в данный сокет. Произвольный IP-адрес и порт может посылать дейтаграммы в неподключенный UDP-сокет, который требуется в некоторых случаях (именно через него новые клиенты впервые связываются с серверами), однако при этом программы должны отслеживать место отправки дейтаграмм.
17.6.2. Отправка и получение дейтаграмм
Для отправки и получения UDP-пакетов обычно используются четыре системных вызова [141] Данные функции могут применяться для передачи данных через любой сокет, и иногда возникают причины для использования их в TCP-соединениях.
: send()
, sendto()
, recv()
, recvfrom()
[142] Возможно также применение системных вызовов sendmsg() и recvmsg() , однако необходимость в этом встречается редко.
.
Читать дальше