Уильям Стивенс - UNIX: разработка сетевых приложений
- Название:UNIX: разработка сетевых приложений
- Автор:
- Жанр:
- Издательство:Питер
- Год:2007
- Город:Санкт-Петербург
- ISBN:5-94723-991-4
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
Уильям Стивенс - UNIX: разработка сетевых приложений краткое содержание
Новое издание книги, посвященной созданию веб-серверов, клиент-серверных приложений или любого другого сетевого программного обеспечения в операционной системе UNIX, — классическое руководство по сетевым программным интерфейсам, в частности сокетам. Оно основано на трудах Уильяма Стивенса и полностью переработано и обновлено двумя ведущими экспертами по сетевому программированию. В книгу включено описание ключевых современных стандартов, реализаций и методов, она содержит большое количество иллюстрирующих примеров и может использоваться как учебник по программированию в сетях, так и в качестве справочника для опытных программистов.
UNIX: разработка сетевых приложений - читать онлайн бесплатно ознакомительный отрывок
Интервал:
Закладка:
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.
Листинг 22.9. Макрос RTT_RTOCALC, функции rtt_minmax и rtt_init
//lib/rtt.c
1 #include "unprtt.h"
2 int rtt_d_flag = 0; /* отладочный флаг; может быть установлен в
ненулевое значение вызывающим процессом */
3 /* Вычисление значения RTO на основе текущих значений:
4 * сглаженное оценочное значение RTT + четырежды сглаженная
5 * величина отклонения.
6 */
7 #define RTI_RTOCALC(ptr) ((ptr)->rtt_srtt + (4.0 * (ptr)->rtt_rttvar))
8 static float
9 rtt_minmax(float rto)
10 {
11 if (rto < RTT_RXTMIN)
12 rto = RTT_RXTMIN;
13 else if (rto > RTT_RXTMAX)
14 rto = RTT_RXTMAX;
15 return (rto);
16 }
17 void
18 rtt_init(struct rtt_info *ptr)
19 {
20 struct timeval tv;
21 Gettimeofday(&tv, NULL);
22 ptr->rtt_base = tv.tv_sec; /* количество секунд, прошедших с 1.1.1970 */
23 ptr->rtt_rtt = 0;
24 ptr->rtt_srtt = 0;
25 ptr->rtt_rttvar = 0.75;
26 ptr->rtt_rto = rtt_minmax(RTT_RTOCALC(ptr));
27 /* первое RTO (srtt + (4 * rttvar)) = 3 с */
28 }
3-7
Макрос вычисляет RTO как сумму оценочной величины RTT и оценочной величины среднего отклонения, умноженной на четыре.
8-16
Функция rtt_minmax
проверяет, что RTO находится между верхним и нижним пределами, заданными в заголовочном файле unprtt.h
.
17-28
Функция rtt_init
вызывается функцией dg_send_recv
при первой отправке пакета. Функция gettimeofday
возвращает текущее время и дату в той же структуре timeval
, которую мы видели в функции select
(см. раздел 6.3). Мы сохраняем только текущее количество секунд с момента начала эпохи Unix, то есть с 00:00:00 1 января 1970 года (UTC). Измеряемое значение RTT обнуляется, а сглаженная оценка RTT и среднее отклонение принимают соответственно значение 0 и 0,75, в результате чего начальное RTO равно 3 с (4×0,75).
В листинге 22.10 показаны следующие три функции RTT.
Листинг 22.10. Функции rtt_ts, rtt_newpack и rtt_start
//lib/rtt.c
34 uint32_t
35 rtt_ts(struct rtt_info *ptr)
36 {
37 uint32_t ts;
38 struct timeval tv;
39 Gettimeofday(&tv, NULL);
40 ts = ((tv.tv_sec - ptr->rtt_base) * 1000) + (tv.tv_usec / 1000);
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 удваивается — в этом и заключается экспоненциальное смещение.
Интервал:
Закладка: