Чтение онлайн

на главную

Жанры

UNIX: разработка сетевых приложений
Шрифт:

19 struct iovec iovsend[2], iovrecv[2];

20 if (rttinit == 0) {

21 rtt_init(&rttinfo); /* первый вызов */

22 rttinit = 1;

23 rtt_d_flag = 1;

24 }

25 sendhdr.seq++;

26 msgsend.msg_name = destaddr;

27 msgsend.msg_namelen = destlen;

28 msgsend.msg_iov = iovsend;

29 msgsend.msg_iovlen = 2;

30 iovsend[0].iov_base = &sendhdr;

31 iovsend[0].iov_len = sizeof(struct hdr);

32 iovsend[1].iov_base = outbuff;

33 iovsend[1].iov_len = outbytes;

34 msgrecv.msg_name = NULL;

35 msgrecv.msg_namelen = 0;

36 msgrecv.msg_iov = iovrecv;

37 msgrecv.msg_iovlen = 2;

38 iovrecv[0].iov_base = &recvhdr;

39 iovrecv[0].iov_len = sizeof(struct hdr);

40 iovrecv[l].iov_base = inbuff;

41 iovrecv[l].iov_len = inbytes;

1-5
Мы включаем новый заголовочный файл
unprtt.h
, показанный в листинге 22.8, который определяет структуру
rtt_info
, содержащую информацию RTT для клиента. Мы определяем одну из этих структур и ряд других переменных.

Определение структур msghdr и структуры hdr

6-10
Мы хотим скрыть от вызывающего процесса добавление порядкового номера и отметки времени в начало каждого пакета. Проще всего использовать для этого функцию
writev
, записав свой заголовок (структура
hdr
), за которым следуют данные вызывающего процесса, в виде одной дейтаграммы UDP. Вспомните, что результатом выполнения функции
writev
на дейтаграммном сокете является отправка одной дейтаграммы. Это проще, чем заставлять вызывающий процесс выделять для нас место в начале буфера, а также быстрее, чем копировать наш заголовок и данные вызывающего процесса в один буфер (под который мы должны выделить память) для каждой функции
sendto
. Но поскольку мы работаем с UDP и нам необходимо задать адрес получателя, следует использовать возможности, предоставляемые структурой
iovec
функций
sendmsg
и
recvmsg
и отсутствующие в функциях
sendto
и
recvfrom
. Вспомните из раздела 14.5, что в некоторых системах доступна более новая структура
msghdr
, включающая вспомогательные данные (
msg_control
), тогда как в более старых системах вместо них применяются элементы
msg_accright
(так называемые права доступа — access rights), расположенные в конце структуры. Чтобы избежать усложнения кода директивами
#ifdef
для обработки этих различий, мы объявляем две структуры
msghdr
как
static
. При этом они инициализируются только нулевыми битами, а затем неиспользованные элементы в конце структур просто игнорируются.

Инициализация
при первом вызове

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
устанавливает счетчик повторных передач в нуль.

Отправка дейтаграммы
Поделиться:
Популярные книги

Назад в СССР: 1986 Книга 5

Гаусс Максим
5. Спасти ЧАЭС
Фантастика:
попаданцы
альтернативная история
5.75
рейтинг книги
Назад в СССР: 1986 Книга 5

Неудержимый. Книга III

Боярский Андрей
3. Неудержимый
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Неудержимый. Книга III

Мастер 3

Чащин Валерий
3. Мастер
Фантастика:
героическая фантастика
попаданцы
аниме
5.00
рейтинг книги
Мастер 3

Конструктор

Семин Никита
1. Переломный век
Фантастика:
попаданцы
альтернативная история
4.50
рейтинг книги
Конструктор

Наследник Четырех

Вяч Павел
5. Игра топа
Фантастика:
героическая фантастика
рпг
6.75
рейтинг книги
Наследник Четырех

Чехов. Книга 2

Гоблин (MeXXanik)
2. Адвокат Чехов
Фантастика:
фэнтези
альтернативная история
аниме
5.00
рейтинг книги
Чехов. Книга 2

Легат

Прокофьев Роман Юрьевич
6. Стеллар
Фантастика:
боевая фантастика
рпг
6.73
рейтинг книги
Легат

Земная жена на экспорт

Шах Ольга
Любовные романы:
любовно-фантастические романы
5.57
рейтинг книги
Земная жена на экспорт

Идеальный мир для Лекаря 11

Сапфир Олег
11. Лекарь
Фантастика:
фэнтези
аниме
5.00
рейтинг книги
Идеальный мир для Лекаря 11

Столичный доктор. Том II

Вязовский Алексей
2. Столичный доктор
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Столичный доктор. Том II

Столичный доктор. Том III

Вязовский Алексей
3. Столичный доктор
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Столичный доктор. Том III

Пропала, или Как влюбить в себя жену

Юнина Наталья
2. Исцели меня
Любовные романы:
современные любовные романы
6.70
рейтинг книги
Пропала, или Как влюбить в себя жену

Нефилим

Демиров Леонид
4. Мания крафта
Фантастика:
фэнтези
боевая фантастика
рпг
7.64
рейтинг книги
Нефилим

Бывший муж

Рузанова Ольга
Любовные романы:
современные любовные романы
5.00
рейтинг книги
Бывший муж