Читаем UNIX: разработка сетевых приложений полностью

 формирование запроса

 signal(SIGALRM, sig_alrm); /* устанавливаем обработчик сигнала */

 rtt_newpack(); /* инициализируем значение счетчика rexmt нулем */

sendagain:

 sendto();

 alarm(rtt_start()); /* задаем аргумент функции alarm равным RTO */

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

  if (rtt_timeout()) /* удваиваем RTO, обновляем оценочные значения */

   отказываемся от дальнейших попыток

  goto sendagain; /* повторная передача */

 }

 do {

  recvfrom();

 } while (неправильный порядковый номер);

 alarm(0); /* отключаем сигнал alarm */

 rtt_stop(); /* вычисляем RTT и обновляем оценочные значения */

 обрабатываем ответ

}

void sig_alrm(int signo) {

 siglongjmp(jmpbuf, 1);

}

Если приходит ответ, но его порядковый номер отличается от предполагаемого, мы снова вызываем функцию recvfrom, но не отправляем снова тот же запрос и не перезапускаем работающий таймер повторной передачи. Обратите внимание, что в крайнем правом случае на рис. 22.2 последний ответ, полученный на отправленный повторно запрос, будет находиться в приемном буфере сокета до тех пор, пока клиент не решит отправить следующий запрос (и получить на него ответ). Это нормально, поскольку клиент прочитает этот ответ, отметит, что порядковый номер отличается от предполагаемого, проигнорирует ответ и снова вызовет функцию recvfrom.

Мы вызываем функции sigsetjmp и siglongjmp, чтобы предотвратить возникновение ситуации гонок с сигналом SIGALRM, который мы описали в разделе 20.5. В листинге 22.6 показана первая часть нашей функции dg_send_recv.

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

//rtt/dg_send_recv.c

 1 #include "unprtt.h"

 2 #include

 3 #define RTT_DEBUG

 4 static struct rtt_info rttinfo;

 5 static int rttinit = 0;

 6 static struct msghdr msgsend, msgrecv;

   /* предполагается, что обе структуры инициализированы нулем */

 7 static struct hdr {

 8  uint32_t seq; /* порядковый номер */

 9  uint32_t ts;  /* отметка времени при отправке */

10 } sendhdr, recvhdr;

11 static void signalrm(int signo);

12 static sigjmp_buf jmpbuf;

13 ssize_t

14 dg_send_recv(int fd, const void *outbuff, size_t outbytes,

15  void *inbuff, size_t inbytes,

16  const SA *destaddr, socklen_t destlen)

17 {

18  ssize_t n;

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;

Перейти на страницу:

Все книги серии Мастер-класс

Секреты резьбы по дереву
Секреты резьбы по дереву

Изделия из древесины и материалов, имитирующих ее текстуру, привычным образом окружают нас в повседневной жизни, поэтому мы относимся к ней как к чему-то обыденному. Но как только ее коснется умелая рука мастера резьбы по дереву, рождается произведение искусства и раскрываются такие качества древесины, как богатая фактура, разнообразие цветов, особая теплота. Эта книга поможет читателю открыть для себя удивительный мир творчества и познать секреты резьбы по дереву. Автор надеется, что начинающие резчики найдут в ней интересный и полезный материал, который позволит им стать мастерами. В приложении представлены рисунки орнаментов и различных узоров, которые на первых порах можно копировать, а по мере приобретения навыка на их основе разрабатывать свои образцы.

Галина Алексеевна Серикова

Сделай сам / Хобби и ремесла / Руководства / Дом и досуг / Словари и Энциклопедии

Похожие книги