Чтение онлайн

ЖАНРЫ

UNIX: разработка сетевых приложений
Шрифт:

32 len = servlen;

33 n = Recvfrom(sockfd, recvline, MAXLINE, 0, preply_addr,

34 &len);

35 recvline[n] = 0; /* null terminate */

36 printf("from %s: %s",

37 Sock_ntop_host(preply_addr, len), recvline);

38 }

39 if (FD_ISSET(pipefd[0], &rset)) {

40 Read(pipefd[0], &n, 1); /* истекшее время */

41 break;

42 }

43 }

44 }

45 free(preply_addr);

46 }

47 static void

48 recvfrom_alarm(int signo)

49 {

50 Write(pipefd[1], "", 1); /*
в канал пишется один нулевой байт */

51 return;

52 }

Создание канала

15
Мы создаем обычный канал Unix. Возвращаются два дескриптора:
pipefd[0]
доступен для чтения, а
pipefd[0]
— для записи.

ПРИМЕЧАНИЕ

Мы могли бы использовать функцию socketpair и получить двусторонний канал. В некоторых системах, особенно SVR4, обычный канал Unix всегда является двусторонним, и мы можем и читать, и записывать на любом конце этого канала.

Функция select на сокете и считывающем конце канала

23-30
Мы вызываем функцию
select
и на сокете, и на считывающем конце канала.

47-52
Когда доставляется сигнал
SIGALRM
, наш обработчик сигналов записывает в канал 1 байт, в результате чего считывающий конец канала становится готовым для чтения. Наш обработчик сигнала также возвращает управление, возможно, прерывая функцию
select
. Следовательно, если функция
select
возвращает ошибку
EINTR
, мы игнорируем эту ошибку, зная, что считывающий конец канала также готов для чтения, что завершит цикл
for
.

Чтение из канала

38-41
Когда считывающий конец канала готов для чтения, мы с помощью функции read считываем нулевой байт, записанный обработчиком сигнала, и игнорируем его. Но прибытие этого нулевого байта указывает нам на то, что истекло время таймера, и мы с помощью функции
break
выходим из бесконечного цикла
for
.

20.6. Резюме

При широковещательной передаче посылается дейтаграмма, которую получают все узлы. Недостатком широковещательной передачи является то, что каждый узел в подсети должен обрабатывать дейтаграмму, вплоть до уровня UDP в случае дейтаграммы UDP, даже если на узле не выполняется приложение-адресат. Для приложений с большими потоками данных, таких как аудио- и видео-приложения, это может привести к повышенной нагрузке на все узлы. В следующей главе мы увидим, что многоадресная передача решает эту проблему, поскольку позволяет не получать дейтаграмму узлам, не заинтересованным в этом.

Использование версии нашего эхо-клиента UDP, который отправляет серверу времени и даты широковещательные дейтаграммы и затем выводит все его ответы, полученные в течение 5 с, позволяет нам рассмотреть ситуацию гонок, возникающую при применении сигнала

SIGALRM
. Общим способом помещения тайм-аута в операцию чтения является использование функции
alarm
и сигнала
SIGALRM
, но он несет в себе неявную ошибку, типичную для сетевых приложений. Мы показали один некорректный
и три корректных способа решения этой проблемы:

использование функции

pselect
,

использование функций

sigsetjmp
и
siglongjmp
,

использование средств IPC (обычно канала) между обработчиком сигнала и главным циклом.

Упражнения

1. Запустите клиент UDP, используя функцию

dg_cli
, выполняющую широковещательную передачу (см. листинг 20.1). Сколько ответов вы получаете? Всегда ли ответы приходят в одном и том же порядке? Синхронизированы ли часы у узлов в вашей подсети?

2. Поместите несколько функций

printf
в листинг 20.6 после завершения функции
select
, чтобы увидеть, возвращает ли она ошибку или указание на готовность к чтению одного из двух дескрипторов. Возвращает ли ваша система ошибку
EINTR
или сообщение о готовности канала к чтению, когда истекает время таймера
alarm
?

3. Запустите такую программу, как

tcpdump
, если это возможно, и просмотрите широковещательные пакеты в вашей локальной сети (команда
tcpdump ether broadcast
). К каким наборам протоколов относятся эти широковещательные пакеты?

Глава 21

Многоадресная передача

21.1. Введение

Как показано в табл. 20.1, адрес направленной передачи идентифицирует одиночныйинтерфейс, широковещательный адрес идентифицирует всеинтерфейсы в подсети, а адрес многоадресной передачи — набор( множество) интерфейсов. Направленная и широковещательная передача — это конечные точки спектра адресации (один интерфейс или все), а цель многоадресной передачи — обеспечить возможность адресации на участок спектра между этими конечными точками. Дейтаграмму многоадресной передачи должны получать только заинтересованные в ней интерфейсы, то есть интерфейсы на тех узлах, на которых запущены приложения, желающие принять участие в сеансе многоадресной передачи. Кроме того, широковещательная передача обычно ограничена локальными сетями, в то время как многоадресная передача может использоваться как в локальной, так и в глобальной сети. Существуют приложения, которые ежедневно участвуют в многоадресной передаче через всю сеть Интернет.

Дополнения к API сокетов, необходимые для поддержки многоадресной передачи, — это девять параметров сокетов. Три из них влияют на отправку дейтаграмм UDP на адрес, а шесть — на получение узлом дейтаграмм многоадресной передачи.

21.2. Адрес многоадресной передачи

При описании адресов многоадресной передачи необходимо провести различия между IPv4 и IPv6.

Адреса IPv4 класса D

Адреса класса D, лежащие в диапазоне от 224.0.0.0 до 239.255.255.255, в IPv4 являются адресами многоадресной передачи (см. табл. А.1). Младшие 28 бит адреса класса D образуют идентификатор группы многоадресной передачи( multicast group ID), а 32-разрядный адрес называется адресом группы( group address).

На рис. 21.1 показано, как адреса многоадресной передачи сопоставляются адресам Ethernet. Сопоставление адресов групп IPv4 для сетей Ethernet описывается в RFC 1112 [26], для сетей FDDI — в RFC 1390 [59], а для сетей типа Token Ring — в RFC 1469 [97]. Чтобы обеспечить возможность сравнения полученных в результате адресов Ethernet, мы также показываем сопоставление для адресов групп Ipv6.

Поделиться с друзьями: