48
Мы устанавливаем буфер перехода для нашего обработчика сигналов с помощью функции sigsetjmp. Мы ждем прихода следующей дейтаграммы, вызывая функцию recvmsg
. (Совместное использование функций sigsetjmp
и siglongjmp
вместе с сигналом SIGALRM
мы обсуждали применительно к листингу 20.5.) Если время таймера истекает, функция sigsetjmp
возвращает 1.
49-55
Когда возникает тайм-аут, функция rtt_timeout
вычисляет следующее значение RTO (используя экспоненциальное смещение) и возвращает -1, если нужно прекратить попытки передачи дейтаграммы, или 0, если нужно выполнить очередную повторную передачу. Когда мы прекращаем попытки, мы присваиваем переменной errno
значение ETIMEDOUT
и возвращаемся в вызывающую функцию.
57-59
Мы ждем прихода дейтаграммы, вызывая функцию recvmsg
. Длина полученной дейтаграммы не должна быть меньше размера структуры hdr
, а ее порядковый номер должен совпадать с порядковым номером запроса, ответом на который предположительно является эта дейтаграмма. Если при сравнении хотя бы одно из этих условий не выполняется, функция recvmsg
вызывается снова.
60-62
Когда приходит ожидаемый ответ, функция alarm
отключается, а функция rtt_stop
обновляет оценочное значение RTT. Функция rtt_ts
возвращает текущую отметку времени, и отметка времени из полученной дейтаграммы вычитается из текущей отметки, что дает в результате RTT.
65-69
Вызывается функция siglongjmp
, результатом выполнения которой является то, что функция sigsetjmp
в dg_send_recv
возвращает 1.
Теперь мы рассмотрим различные функции RTT, которые вызывались нашей функцией dg_send_recv
. В листинге 22.8 показан заголовочный файл unprtt.h
.
Листинг 22.8. Заголовочный файл unprtt.h
//lib/unprtt.h
1 #ifndef __unp_rtt_h
2 #define __unp_rtt_h
3 #include "unp.h"
4 struct rtt_info {
5 float rtt_rtt; /* последнее измеренное значение RTT в секундах */
6 float rtt_srtt; /* сглаженная оценка RTT в секундах */
7 float rtt_rttvar; /* сглаженные средние значения отклонений
в секундах */
8 float rtt_rto; /* текущее используемое значение RTO, в секундах */
9 int rtt_nrexmt; /* количество повторных передач: 0, 1, 2, ... */
10 uint32_t rtt_base; /* число секунд, прошедшее после 1.1.1970 в начале */
11 };
12 #define RTT_RXTMIN 2 /* минимальное значение тайм-аута для
повторной передачи, в секундах */
13 #define RTT_RXTMAX 60 /* максимальное значение тайм-аута для
повторной передачи, в секундах */
14 #define RTT_MAXNREXMT 3 /* максимально допустимое количество
повторных передач одной дейтаграммы */
15 /* прототипы функций */
16 void rtt_debug(struct rtt_info*);
17 void rtt_init(struct rtt_info*);
18 void rtt_newpack(struct rtt_info*);
19 int rtt_start(struct rtt_info*);
20 void rtt_stop(struct rtt_info*, uint32_t);
21 int rtt_timeout(struct rtt_info*);
22 uint32_t rtt_ts(struct rtt_info*);
23 extern int rtt_d_flag; /* может быть ненулевым при наличии
дополнительной информации */
24 #endif /* _unp_rtt_h */
4-11
Эта структура содержит переменные, необходимые для того, чтобы определить время передачи пакетов между клиентом и сервером. Первые четыре переменных взяты из уравнений, приведенных в начале этого раздела.
12-14
Эти константы определяют минимальный и максимальный тайм-ауты повторной передачи и максимальное число возможных повторных передач.
В листинге 22.9 показан макрос RTT_RTOCALC
и первые две из четырех функций RTT.