UNIX: разработка сетевых приложений
UNIX: разработка сетевых приложений читать книгу онлайн
Новое издание книги, посвященной созданию веб-серверов, клиент-серверных приложений или любого другого сетевого программного обеспечения в операционной системе UNIX, — классическое руководство по сетевым программным интерфейсам, в частности сокетам. Оно основано на трудах Уильяма Стивенса и полностью переработано и обновлено двумя ведущими экспертами по сетевому программированию. В книгу включено описание ключевых современных стандартов, реализаций и методов, она содержит большое количество иллюстрирующих примеров и может использоваться как учебник по программированию в сетях, так и в качестве справочника для опытных программистов.
Внимание! Книга может содержать контент только для совершеннолетних. Для несовершеннолетних чтение данного контента СТРОГО ЗАПРЕЩЕНО! Если в книге присутствует наличие пропаганды ЛГБТ и другого, запрещенного контента - просьба написать на почту [email protected] для удаления материала
Узел, изображенный справа, передает дейтаграмму UDP приложению, связанному с портом UDP 520. Приложению не нужно выполнять никаких специальных действий, чтобы получить широковещательную дейтаграмму UDP — оно лишь создает сокет UDP и связывает номер приложения порта с сокетом. (Предполагается, как обычно, что связанный IP-адрес —
INADDR_ANY
Но на узле, изображенном в центре, с портом UDP 520 не связано никакое приложение. UDP этого узла игнорирует полученную дейтаграмму. Узел не должен отправлять сообщение ICMP о недоступности порта, поскольку это может вызвать лавину широковещательных сообщений (broadcast storm): ситуацию, в которой множество узлов сети генерируют ответы приблизительно в одно и то же время, в результате чего сеть просто невозможно использовать в течение некоторого времени. Кроме того, не совсем понятно, что должен предпринять получатель сообщения об ошибке: что, если некоторые получатели будут сообщать об ошибках, а другие — нет?
В этом примере мы также показываем дейтаграмму, которую изображенный слева узел доставляет сам себе. Это свойство широковещательных сообщений: по определению широковещательное сообщение идет к каждому узлу подсети, включая отправляющий узел [128, с. 109–110]. Мы также предполагаем, что отправляющее приложение связано с портом, на который оно отправляет дейтаграммы (порт 520), поэтому оно получит копию каждой отправленной им широковещательной дейтаграммы. (Однако в общем случае не требуется, чтобы процесс связывался с портом UDP, на который он отправляет дейтаграммы.)
В этом примере мы демонстрируем закольцовку, которая осуществляется либо на уровне IP, либо на канальном уровне, создающем копию [128, с. 109-110] и отправляющем ее вверх по стеку протоколов. Сеть могла бы использовать физическую закольцовку, но это может вызвать проблемы в случае сбоев сети (например, линия Ethernet без терминатора).
Этот пример отражает фундаментальную проблему, связанную с широковещательной передачей: каждый узел IPv4 в подсети, даже не выполняющий соответствующего приложения, должен полностью обрабатывать широковещательную дейтаграмму UDP при ее прохождении вверх по стеку протоколов, включая уровень UDP, прежде чем сможет ее проигнорировать. (Вспомните наше обсуждение следом за листингом 8.11). Более того, каждый не-IP-узел в подсети (скажем, узел, на котором работает IPX Novell) должен также получать целый кадр на канальном уровне, перед тем как он сможет проигнорировать этот кадр (в данном случае мы предполагаем, что узел не поддерживает кадры определенного типа — для дейтаграммы IPv4 тип равен
0x0800
Для рис. 20.3 мы специально выбрали порт UDP 520. Это порт, используемый демоном routed для обмена пакетами по протоколу информации о маршрутизации (Routing Information Protocol, RIP). Все маршрутизаторы в подсети, использующие RIP, будут отправлять широковещательную дейтаграмму UDP каждые 30 секунд. Если в подсети имеется 200 узлов, в том числе два маршрутизатора, использующих RIP, то 198 узлов должны будут обрабатывать (и игнорировать) эти широковещательные дейтаграммы каждые 30 с, если ни на одном из них не запущен демон routed. Протокол RIP версии 2 использует многоадресную передачу именно для того, чтобы избавиться от этой проблемы.
20.4. Функция dg_cli при использовании широковещательной передачи
Мы еще раз изменим нашу функцию
dg_cli
main
servaddr.sin_port = htons(13);
Сначала мы откомпилируем измененную функцию
main
dg_cli
freebsd
freebsd % <b>udpcli01 192.168.42.255</b>
<b>hi</b>
sendto error: Permission denied
Аргумент командной строки — это широковещательный адрес подсети для присоединенной сети Ethernet. Мы вводим строку, программа вызывает функцию
sendto
EACCESS
SO_BROADCAST
Беркли-реализации реализуют эту «защиту от дурака» (sanity check). Однако Solaris 2.5 принимает дейтаграмму, предназначенную для широковещательного адреса, даже если мы не задаем параметр сокета SO_BROADCAST. Стандарт POSIX требует установки параметра сокета SO_BROADCAST для отправки широковещательной дейтаграммы.
В 4.2BSD широковещательная передача была привилегированной операцией, и параметра сокета SO_BROADCAST не существовало. В 4.3BSD этот параметр был добавлен и каждому процессу стало разрешено его устанавливать.
Теперь мы изменим нашу функцию
dg_cli
SO_BROADCAST
Листинг 20.1. Функция dg_cli, осуществляющая широковещательную передачу
//bcast/dgclibcast1.c
1 #include "unp.h"
2 static void recvfrom_alarm(int);
3 void
4 dg_cli(FILE *fp, int sockfd, const SA *pservaddr, socklen_t servlen)
5 {
6 int n;
7 const int on = 1;
8 char sendline[MAXLINE], recvline[MAXLINE + 1];
9 socklen_t len;
10 struct sockaddr *preply_addr;
11 preply_addr = Malloc(servlen);
12 Setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on));
13 Signal(SIGALRM, recvfrom_alarm);
14 while (Fgets(sendline, MAXLINE, fp) != NULL) {
15 Sendto(sockfd, sendline, strlen(sendline), 0, pservaddr, servlen);