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

 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 заблокируется навсегда. Мы ограничили размер окна, но проблема осталась.

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

recvfrom_alarm(int signo) {

 had_alarm = 1;

 return;

}

Флаг сбрасывается в 0 каждый раз, когда вызывается функция alarm. Наша функция dg_cli проверяет этот флаг перед вызовом функции recvfrom и не вызывает ее, если флаг ненулевой.

for (;;) {

 len = servlen;

 Sigprocmask(SIG_UNBLOCK, &sigset_alrm, NULL);

 if (had_alarm == 1)

  break;

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

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

Все книги серии Мастер-класс

Секреты резьбы по дереву
Секреты резьбы по дереву

Изделия из древесины и материалов, имитирующих ее текстуру, привычным образом окружают нас в повседневной жизни, поэтому мы относимся к ней как к чему-то обыденному. Но как только ее коснется умелая рука мастера резьбы по дереву, рождается произведение искусства и раскрываются такие качества древесины, как богатая фактура, разнообразие цветов, особая теплота. Эта книга поможет читателю открыть для себя удивительный мир творчества и познать секреты резьбы по дереву. Автор надеется, что начинающие резчики найдут в ней интересный и полезный материал, который позволит им стать мастерами. В приложении представлены рисунки орнаментов и различных узоров, которые на первых порах можно копировать, а по мере приобретения навыка на их основе разрабатывать свои образцы.

Галина Алексеевна Серикова

Сделай сам / Хобби и ремесла / Руководства / Дом и досуг / Словари и Энциклопедии

Похожие книги