Вход/Регистрация
UNIX: разработка сетевых приложений
вернуться

Стивенс Уильям Ричард

Шрифт:

15 Signal(SIGALRM, recvfrom_alarm);

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

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

18 alarm(5);

19 for (;;) {

20 if (sigsetjmp(jmpbuf, 1) != 0)

21 break;

22 len = servlen;

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

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

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

26 Sock_ntop_host(preply_addr, len), recvline);

27 }

28 }

29 free(preply_addr);

30 }

31 static void

32 recvfrom_alarm(int signo)

33 {

34 siglongjmp(jmpbuf, 1);

35 }

Размещение буфера перехода в памяти

4
Мы выделяем буфер перехода, который будет использовать наша функция и ее обработчик сигнала.

Вызов функции sigsetjmp

20-23
Когда мы вызываем функцию
sigsetjmp
непосредственно из нашей функции
dg_cli
, она устанавливает буфер перехода и возвращает нуль. Мы продолжаем работать дальше и вызываем функцию
recvfrom
.

Обработка сигнала SIGALRM и вызов функции siglongjmp

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

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

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

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

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

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);

  • Читать дальше
  • 1
  • ...
  • 278
  • 279
  • 280
  • 281
  • 282
  • 283
  • 284
  • 285
  • 286
  • 287
  • 288
  • ...

Ебукер (ebooker) – онлайн-библиотека на русском языке. Книги доступны онлайн, без утомительной регистрации. Огромный выбор и удобный дизайн, позволяющий читать без проблем. Добавляйте сайт в закладки! Все произведения загружаются пользователями: если считаете, что ваши авторские права нарушены – используйте форму обратной связи.

Полезные ссылки

  • Моя полка

Контакты

  • chitat.ebooker@gmail.com

Подпишитесь на рассылку: