Литмир - Электронная Библиотека
Содержание  
A
A
Инициализация при первом вызове

20-24
 При первом вызове нашей функции мы вызываем функцию
rtt_init
.

Заполнение структур msghdr

25-41
 Мы заполняем две структуры
msghdr
, используемые для ввода и вывода. Для данного пакета мы увеличиваем на единицу порядковый номер отправки, но не устанавливаем отметку времени отправки, пока пакет не будет отправлен (поскольку он может отправляться повторно, а для каждой повторной передачи требуется текущая отметка времени).

Вторая часть функции вместе с обработчиком сигнала

sig_alarm
показана в листинге 22.7.

Листинг 22.7. Функция dg_send_recv: вторая половина

//rtt/dg_send_rеcv.c

42  Signal(SIGALRM, sig_alrm);

43  rtt_newpack(&rttinfo); /* инициализируем для этого пакета */

44 sendagain:

45  sendhdr.ts = rtt_ts(&rttinfo);

46  Sendmsg(fd, &msgsend, 0);

47  alarm(rtt_start(&rttinfo)); /* вычисляем тайм-аут. запускаем таймер */

48  if (sigsetjmp(jmpbuf, 1) != 0) {

49   if (rtt_timeout(&rttinfо) < 0) {

50    err_msg("dg_send_recv: no response from server, giving up");

51    rttinit = 0; /* повторная инициализация для следующего вызова */

52    errno = ETIMEDOUT;

53    return (-1);

54   }

55   goto sendagain;

56  }

57  do {

58   n = Recvmsg(fd, &msgrecv, 0);

59  } while (n < sizeof(struct hdr) || recvhdr.seq != sendhdr.seq);

60  alarm(0); /* останавливаем таймер SIGALRM */

61  /* вычисляем и записываем новое значение оценки RTT */

62  rtt_stop(&rttinfo, rtt_ts(&rttinfo) — recvhdr.ts);

63  return (n - sizeof(struct hdr)); /* возвращаем размер полученной

                                        дейтаграммы */

64 }

65 static void

66 sig_alrm(int signo)

67 {

68  siglongjmp(jmpbuf, 1);

69 }

Установка обработчика сигналов

42-43
 Для сигнала
SIGALRM
устанавливается обработчик сигналов, а функция
rtt_newpack
устанавливает счетчик повторных передач в нуль.

Отправка дейтаграммы

45-47
 Функция
rtt_ts
получает текущую отметку времени. Отметка времени хранится в структуре
hdr
, которая добавляется к данным пользователя. Одиночная дейтаграмма UDP отправляется функцией
sendmsg
. Функция
rtt_start
возвращает количество секунд для этого тайм-аута, а сигнал
SIGALRM
контролируется функцией
alarm
.

Установка буфера перехода

48
 Мы устанавливаем буфер перехода для нашего обработчика сигналов с помощью функции sigsetjmp. Мы ждем прихода следующей дейтаграммы, вызывая функцию
recvmsg
. (Совместное использование функций
sigsetjmp
и
siglongjmp
вместе с сигналом
SIGALRM
мы обсуждали применительно к листингу 20.5.) Если время таймера истекает, функция
sigsetjmp
возвращает 1.

Обработка тайм-аута

49-55
 Когда возникает тайм-аут, функция
rtt_timeout
вычисляет следующее значение RTO (используя экспоненциальное смещение) и возвращает -1, если нужно прекратить попытки передачи дейтаграммы, или 0, если нужно выполнить очередную повторную передачу. Когда мы прекращаем попытки, мы присваиваем переменной
errno
значение
ETIMEDOUT
и возвращаемся в вызывающую функцию.

Вызов функции recvmsg, сравнение порядковых номеров

57-59
 Мы ждем прихода дейтаграммы, вызывая функцию
recvmsg
. Длина полученной дейтаграммы не должна быть меньше размера структуры
hdr
, а ее порядковый номер должен совпадать с порядковым номером запроса, ответом на который предположительно является эта дейтаграмма. Если при сравнении хотя бы одно из этих условий не выполняется, функция
recvmsg
вызывается снова.

Выключение таймера и обновление показателей RTT

60-62
 Когда приходит ожидаемый ответ, функция
alarm
отключается, а функция
rtt_stop
обновляет оценочное значение RTT. Функция
rtt_ts
возвращает текущую отметку времени, и отметка времени из полученной дейтаграммы вычитается из текущей отметки, что дает в результате RTT.

Обработчик сигнала SIGALRM

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 {

250
{"b":"225366","o":1}