Страница 154 из 399
Мы также рассказываем о том, как определить, сколько данных находится в приемном буфере сокета и как использовать с сокетами стандартную библиотеку ввода-вывода С, и обсуждаем более совершенные способы ожидания событий.
14.2. Тайм-ауты сокета
Существует три способа установки тайм-аута для операции ввода-вывода через сокет.
1. Вызов функции alarm, которая генерирует сигнал SIGALRM, когда истекает заданное время. Это подразумевает обработку сигналов, которая может варьироваться от одной реализации к другой. К тому же такой подход может стать помехой другим существующим вызовам функции alarm в данном процессе.
2. Блокирование при ожидании ввода-вывода в функции select, имеющей встроенное ограничение времени, вместо блокирования в вызове функции read или write.
3. Использование более новых параметров сокета — SO_RCVTIMEO и SO_SNDTIMEO. Проблема при использовании этого подхода заключается в том, что не все реализации поддерживают новые параметры сокетов.
Все три технологии работают с функциями ввода и вывода (такими как read, write и их вариациями, например recvfrom и sendto), но нам также хотелось бы иметь технологию, работающую с функцией co
Теперь мы представим примеры применения всех трех технологий.
Тайм-аут для функции co
В листинге 14.1[1] показана наша функция co
Листинг 14.1. Функция co
//lib/co
1 #include "unp.h"
2 static void co
3 int
4 co
5 {
6 Sigfunc *sigfunc;
7 int n;
8 sigfunc = Signal(SIGALRM, co
9 if (alarm(nsec) != 0)
10 err_msg("co
11 if ((n = co
12 close(sockfd);
13 if (errno == EINTR)
14 errno = ETIMEDOUT;
15 }
16 alarm(0); /* отключение alarm */
17 Signal(SIGALRM, sigfunc); /* восстанавливаем прежний обработчик
сигнала */
18 return (n);
19 }
20 static void
21 co
22 {
23 return; /* просто прерываем co
24 }
8 Для SIGALRM устанавливается обработчик сигнала. Текущий обработчик сигнала (если таковой имеется) сохраняется, и таким образом мы можем восстановить его в конце функции.
9-10 Таймер для процесса устанавливается на время (число секунд), заданное вызывающим процессом. Возвращаемое значение функции alarm — это число секунд, остающихся в таймере для процесса (если он уже установлен для процесса) в настоящий момент или 0 (если таймер не был установлен прежде). В первом случае мы выводим сообщение с предупреждением, поскольку мы стираем предыдущую установку таймера (см. упражнение 14.2).
11-15 Вызывается функция co
16-18 Таймер при обнулении выключается, и восстанавливается предыдущий обработчик сигналов (если таковой имеется).
20-24 Обработчик сигнала просто возвращает управление. Предполагается, что это прервет ожидание функции co
Одним из важных моментов в этом примере является то, что мы всегда можем сократить период ожидания для функции co
Другой важный момент в данном примере — то, что мы используем возможность прерывания системного вызова (co
1
Все исходные коды программ, опубликованные в этой книге, вы можете найти по адресу http://www.piter.com.