-->

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

На нашем литературном портале можно бесплатно читать книгу UNIX: разработка сетевых приложений, Стивенс Уильям Ричард-- . Жанр: ОС и Сети. Онлайн библиотека дает возможность прочитать весь текст и даже без регистрации и СМС подтверждения на нашем литературном портале bazaknig.info.
UNIX: разработка сетевых приложений
Название: UNIX: разработка сетевых приложений
Дата добавления: 16 январь 2020
Количество просмотров: 386
Читать онлайн

UNIX: разработка сетевых приложений читать книгу онлайн

UNIX: разработка сетевых приложений - читать бесплатно онлайн , автор Стивенс Уильям Ричард

Новое издание книги, посвященной созданию веб-серверов, клиент-серверных приложений или любого другого сетевого программного обеспечения в операционной системе UNIX, — классическое руководство по сетевым программным интерфейсам, в частности сокетам. Оно основано на трудах Уильяма Стивенса и полностью переработано и обновлено двумя ведущими экспертами по сетевому программированию. В книгу включено описание ключевых современных стандартов, реализаций и методов, она содержит большое количество иллюстрирующих примеров и может использоваться как учебник по программированию в сетях, так и в качестве справочника для опытных программистов.

Внимание! Книга может содержать контент только для совершеннолетних. Для несовершеннолетних чтение данного контента СТРОГО ЗАПРЕЩЕНО! Если в книге присутствует наличие пропаганды ЛГБТ и другого, запрещенного контента - просьба написать на почту [email protected] для удаления материала

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

<i> формирование запроса</i>

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

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

sendagain:

 sendto();

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

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

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

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

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

 }

 do {

  recvfrom();

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

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

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

<i> обрабатываем ответ</i>

}

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 &quot;unprtt.h&quot;

 2 #include &lt;setjmp.h&gt;

 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(&amp;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 = &amp;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 = &amp;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
. При этом они инициализируются только нулевыми битами, а затем неиспользованные элементы в конце структур просто игнорируются.

Перейти на страницу:
Комментариев (0)
название