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

31-35 Когда сигнал доставлен, мы вызываем функцию siglongjmp. Это заставляет sigsetjmp в функции dg_cli возвратить значение, равное второму аргументу (1), который должен быть ненулевым. Это приведет к завершению цикла for в функции dg_cli.

Использование функций sigsetjmp и siglongjmp подобным образом гарантирует, что мы не останемся навсегда блокированы в вызове функции recvfrom из-за доставки сигнала в неподходящее время. Однако такое решение создает иную потенциальную проблему. Если сигнал доставляется в тот момент, когда функция printf осуществляет вывод данных, управление будет передано из printf обратно на sigsetjmp. При этом в структурах данных printf могут возникнуть противоречия. Чтобы предотвратить эту проблему, следует объединить блокирование и разблокирование сигналов, показанное в листинге 20.2, с помощью нелокального оператора goto.

<p>Применение IPC в обработчике сигнала функции</p>

Существует еще один корректный путь решения нашей проблемы. Вместо того чтобы просто возвращать управление и, как мы надеемся, прерывать блокированную функцию recvfrom, наш обработчик сигнала при помощи средств IPC (Interprocess Communications — взаимодействие процессов) может сообщить функции dg_cli о том, что время таймера истекло. Это аналогично предложению, сделанному нами раньше, когда обработчик сигнала устанавливал глобальную переменную had_alarm по истечении времени таймера. Глобальная переменная использовалась как некая разновидность IPC (поскольку она была доступна и нашей функции, и обработчику сигнала). Однако при таком решении наша функция должна была проверять эту переменную, что могло привести к проблемам синхронизации в том случае, когда сигнал доставлялся приблизительно в это же время.

Листинг 20.6 демонстрирует использование канала внутри процесса. Обработчик сигналов записывает в канал 1 байт, когда истекает время таймера, а наша функция dg_cli считывает этот байт, чтобы определить, когда завершить свой цикл for. Что замечательно в этом решении — проверка готовности канала осуществляется функцией select. С ее помощью мы проверяем, готов ли к считыванию сокет или канал.

Листинг 20.6. Использование канала в качестве IPC между обработчиком сигнала и нашей функцией

//bcast/dgclibcast6.c

 1 #include "unp.h"

 2 static void recvfrom_alarm(int);

 3 static int pipefd[2];

 4 void

 5 dg_cli(FILE *fp, int sockfd, const SA *pservaddr, socklen_t servlen)

 6 {

 7  int n, maxfdp1;

 8  const int on = 1;

 9  char sendline[MAXLINE], recvline[MAXLINE + 1];

10  fd_set rset;

11  socklen_t len;

12  struct sockaddr *preply_addr;

13  preply_addr = Malloc(servlen);

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

15  Pipe(pipefd);

16  maxfdp1 = max(sockfd, pipefd[0]) + 1;

17  FD_ZERO(&rset);

18  Signal(SIGALRM, recvfrom_alarm);

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

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

21   alarm(5);

22   for (;;) {

23    FD_SET(sockfd, &rset);

24    FD_SET(pipefd[0], &rset);

25    if ((n = select(maxfdp1, &rset, NULL, NULL, NULL)) < 0) {

26     if (errno == EINTR)

27      continue;

28     else

29      err_sys("select error");

30    }

31    if (FD_ISSET(sockfd, &rset)) {

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 }

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

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

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

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

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

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

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