Шрифт:
41 return (ts);
42 }
43 void
44 rtt_newpack(struct rtt_info *ptr)
45 {
46 ptr->rtt_nrexmt = 0;
47 }
48 int
49 rtt_start(struct rtt_info *ptr)
50 {
51 return ((int)(ptr->rtt_rto + 0.5)); /* округляем float до int */
52 /* возвращенное значение может быть использовано как аргумент
alarm(rtt_start(&fоо)) */
53 }
34-42
Функция rtt_ts
возвращает текущую отметку времени для вызывающего процесса, которая должна содержаться в отправляемой дейтаграмме в виде 32-разрядного целого числа без знака. Мы получаем текущее время и дату из функции gettimeofday
и затем вычитаем число секунд в момент вызова функции rtt_init
(значение, хранящееся в элементе rtt_base
структуры rtt_info
). Мы преобразуем это значение в миллисекунды, а также преобразуем в миллисекунды значение, возвращаемое функцией gettimeofday
в микросекундах. Тогда отметка времени является суммой этих двух значений в миллисекундах. Разница во времени между двумя вызовами функции
rtt_ts
представляется количеством миллисекунд между этими двумя вызовами. Но мы храним отметки времени в 32-разрядном целом числе без знака, а не в структуре timeval
.
43-47
Функция rtt_newpack
просто обнуляет счетчик повторных передач. Эта функция должна вызываться всегда, когда новый пакет отправляется в первый раз.
48-53
Функция rtt_start
возвращает текущее значение RTO в миллисекундах. Возвращаемое значение затем может использоваться в качестве аргумента функции alarm
. Функция
rtt_stop
, показанная в листинге 22.11, вызывается после получения ответа для обновления оценочного значения RTT и вычисления нового значения RTO. Листинг 22.11. Функция rtt_stop: обновление показателей RTT и вычисление нового
//lib/rtt.c
62 void
63 rtt_stop(struct rtt_info *ptr, uint32_t ms)
64 {
65 double delta;
66 ptr->rtt_rtt = ms / 1000.0; /* измеренное значение RTT в секундах */
67 /*
68 * Обновляем оценочные значения RTT среднего отклонения RTT.
69 * (См. статью Джекобсона (Jacobson). SIGCOMM'88. Приложение А.)
70 * Здесь мы для простоты используем числа с плавающей точкой.
71 */
72 delta = ptr->rtt_rtt - ptr->rtt_srtt;
73 ptr->rtt_srtt += delta / 8; /* g - 1/8 */
74 if (delta < 0.0)
75 delta = -delta; /* |delta| */
76 ptr->rtt_rttvar += (delta - ptr->rtt_rttvar) / 4; /* h - 1/4 */
77 ptr->rtt_rto = rtt_minmax(RTT_RTOCALC(ptr));
78 }
62-78
Вторым аргументом является измеренное RTT, полученное вызывающим процессом при вычитании полученной в ответе отметки времени из текущей (функция rtt_ts
). Затем применяются уравнения, приведенные в начале этого раздела, и записываются новые значения переменных rtt_srtt
, rtt_rttvar
и rtt_rto
. Последняя функция,
rtt_timeout
показана в листинге 22.12. Эта функция вызывается, когда истекает время таймера повторных передач. Листинг 22.12. Функция rtt_timeout: применение экспоненциального смещения
//lib/rtt.c
83 int
84 rtt_timeout(struct rtt_info *ptr)
85 {
86 ptr->rtt_rto *= 2; /* следующее значение RTO */
87 if (++ptr->rtt_nrexmt > RTT_MAXNREXMT)
88 return (-1); /* закончилось время, отпущенное на попытки отправить
этот пакет */
89 return (0);
90 }
86
Текущее значение RTO удваивается — в этом и заключается экспоненциальное смещение.
87-89
Если мы достигли максимально возможного количества повторных передач, возвращается значение -1, указывающее вызывающему процессу, что дальнейшие попытки передачи должны прекратиться. В противном случае возвращается 0.