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
рейтинг книги
Неудержимый. Книга III
3. Неудержимый
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Мастер 3
3. Мастер
Фантастика:
героическая фантастика
попаданцы
аниме
5.00
рейтинг книги
Конструктор
1. Переломный век
Фантастика:
попаданцы
альтернативная история
4.50
рейтинг книги
Наследник Четырех
5. Игра топа
Фантастика:
героическая фантастика
рпг
6.75
рейтинг книги
Чехов. Книга 2
2. Адвокат Чехов
Фантастика:
фэнтези
альтернативная история
аниме
5.00
рейтинг книги
Легат
6. Стеллар
Фантастика:
боевая фантастика
рпг
6.73
рейтинг книги
Земная жена на экспорт
Любовные романы:
любовно-фантастические романы
5.57
рейтинг книги
Идеальный мир для Лекаря 11
11. Лекарь
Фантастика:
фэнтези
аниме
5.00
рейтинг книги
Столичный доктор. Том II
2. Столичный доктор
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Столичный доктор. Том III
3. Столичный доктор
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Пропала, или Как влюбить в себя жену
2. Исцели меня
Любовные романы:
современные любовные романы
6.70
рейтинг книги
Нефилим
4. Мания крафта
Фантастика:
фэнтези
боевая фантастика
рпг
7.64
рейтинг книги
Бывший муж
Любовные романы:
современные любовные романы
5.00