-->

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

На нашем литературном портале можно бесплатно читать книгу UNIX: разработка сетевых приложений, Стивенс Уильям Ричард-- . Жанр: ОС и Сети. Онлайн библиотека дает возможность прочитать весь текст и даже без регистрации и СМС подтверждения на нашем литературном портале bazaknig.info.
UNIX: разработка сетевых приложений
Название: UNIX: разработка сетевых приложений
Дата добавления: 16 январь 2020
Количество просмотров: 387
Читать онлайн

UNIX: разработка сетевых приложений читать книгу онлайн

UNIX: разработка сетевых приложений - читать бесплатно онлайн , автор Стивенс Уильям Ричард

Новое издание книги, посвященной созданию веб-серверов, клиент-серверных приложений или любого другого сетевого программного обеспечения в операционной системе UNIX, — классическое руководство по сетевым программным интерфейсам, в частности сокетам. Оно основано на трудах Уильяма Стивенса и полностью переработано и обновлено двумя ведущими экспертами по сетевому программированию. В книгу включено описание ключевых современных стандартов, реализаций и методов, она содержит большое количество иллюстрирующих примеров и может использоваться как учебник по программированию в сетях, так и в качестве справочника для опытных программистов.

Внимание! Книга может содержать контент только для совершеннолетних. Для несовершеннолетних чтение данного контента СТРОГО ЗАПРЕЩЕНО! Если в книге присутствует наличие пропаганды ЛГБТ и другого, запрещенного контента - просьба написать на почту [email protected] для удаления материала

Перейти на страницу:

Когда мы после внесения этих изменений наберем первую строку ввода, эта строка будет отправлена как широковещательное сообщение, а мы установим аргумент функции

alarm
равным 1 с. Мы блокируемся в вызове функции
recvfrom
, а затем для нашего сокета приходит первый ответ, вероятно, в течение нескольких миллисекунд. Ответ возвращается функцией
recvfrom
, но затем мы входим в спящее состояние на одну секунду. Принимаются остальные ответы и помещаются в приемный буфер сокета. Но пока мы находимся в спящем состоянии, время таймера
alarm
истекает и генерируется сигнал
SIGALRM
. При этом вызывается наш обработчик сигнала, затем он возвращает управление и прерывает функцию
sleep
, в которой мы блокированы. Далее мы повторяем цикл и читаем установленные в очередь ответы с паузой в одну секунду каждый раз, когда выводится ответ. Прочитав все ответы, мы снова блокируемся в вызове функции
recvfrom
, однако таймер уже не работает. Мы окажемся навсегда заблокированы в вызове функции
recvfrom
. Фундаментальная проблема здесь в том, что наша цель — обеспечить прерывание блокирования в функции
recvfrom
обработчиком сигнала, однако сигнал может быть доставлен в любое время, и наша программа в момент доставки сигнала может находиться в любом месте бесконечного цикла
for
.

Теперь мы проанализируем четыре различных варианта решения этой проблемы: одно некорректное и три различных корректных решения.

Блокирование и разблокирование сигнала

Наше первое (некорректное) решение снижает вероятность появления ошибки, блокируя сигнал и предотвращая его доставку, пока наша программа выполняет оставшуюся часть цикла

for
. Эта версия представлена в листинге 20.2.

Листинг 20.2. Блокирование сигналов при выполнении в цикле for (некорректное решение)

//bcast/dgclibcast3.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  sigset_t sigset_alrm;

10  socklen_t len;

11  struct sockaddr *preply_addr;

12  preply_addr = Malloc(servlen);

13  Setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on));

14  Sigemptyset(&sigset_alrm);

15  Sigaddset(&sigset_alrm, SIGALRM);

16  Signal(SIGALRM, recvfrom_alarm);

17  while (Fgets(sendline, MAXLINE, fp) != NULL) {

18   Sendto(sockfd, sendline, strlen(sendline), 0, pservaddr, servlen);

19   alarm(5);

20   for (;;) {

21    len = servlen;

22    Sigprocmask(SIG_UNBLOCK, &sigset_alrm, NULL);

23    n = recvfrom(sockfd, recvline, MAXLINE, 0, preply_addr, &len);

24    Sigprocmask(SIG_BLOCK, &sigset_alrm, NULL);

25    if (n < 0) {

26     if (errno == EINTR)

27      break; /* окончание ожидания ответа */

28     else

29      err_sys("recvfrom error");

30    } else {

31     recvline[n] = 0; /* завершающий нуль */

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

33     Sock_ntop_host(preply_addr, len), recvline);

34    }

35   }

36  }

37  free(preply_addr);

38 }

39 static void

40 recvfrom_alarm(int signo)

41 {

42  return; /* выход из recvfrom() */

43 }

Объявление набора сигналов и инициализация

14-15
 Мы объявляем набор сигналов, инициализируем его как пустой набор (
sigemptyset
) и включаем бит, соответствующий сигналу
SIGALRM
(
sigaddset
).

Разблокирование и блокирование сигнала

21-24
 Перед вызовом функции
recvfrom
мы разблокируем сигнал (с тем, чтобы он мог быть доставлен, пока наша программа блокирована), а затем блокируем его, как только завершается функция
recvfrom
. Если сигнал генерируется (истекает время таймера), когда сигнал блокирован, то ядро запоминает этот факт, но доставить сигнал (то есть вызвать наш обработчик) не может, пока сигнал не будет разблокирован. В этом состоит принципиальная разница между генерацией сигнала и его доставкой. В главе 10 [110] предоставлена более подробная информация обо всех аспектах обработки сигналов POSIX.

Если мы откомпилируем и запустим эту программу, нам будет казаться, что она работает нормально, но все программы, порождающие ситуацию гонок, большую часть времени работают без каких-либо проблем! Проблема остается: разблокирование сигнала, вызов функции

recvfrom
и блокирование сигнала — все эти действия являются независимыми системными вызовами. Будем считать, что функция
recvfrom
возвращает последний ответ на нашу дейтаграмму, а сигнал доставляется между вызовом функции
recvfrom
и блокированием сигнала. Следующий вызов функции
recvfrom
заблокируется навсегда. Мы ограничили размер окна, но проблема осталась.

Вариантом решения может быть установка глобального флага при доставке сигнала его обработчиком:

Перейти на страницу:
Комментариев (0)
название