Вход/Регистрация
UNIX: разработка сетевых приложений
вернуться

Стивенс Уильям Ричард

Шрифт:

14 dg_cli(stdin, sockfd, (SA*)&servaddr, sizeof(servaddr));

15 exit(0);

16 }

Заполнение структуры адреса сокета адресом сервера

9-12
Структура адреса сокета IPv4 заполняется IP-адресом и номером порта сервера. Эта структура будет передана функции
dg_cli
. Она определяет, куда отправлять дейтаграммы.

13-14
Создается сокет UDP и вызывается функция
dg_cli
.

8.6. Эхо-клиент UDP: функция dg_cli

В листинге 8.4 показана функция

dg_cli
, которая выполняет большую часть работы на стороне клиента.

Листинг 8.4. Функция dg_cli: цикл обработки клиента

//lib/dg_cli.c

1 #include "unp.h"

2 void

3 dg_cli(FILE *fp, int sockfd, const SA *pservaddr, socklen_t servlen)

4 {

5 int n;

6 char sendline[MAXLINE], recvline[MAXLINE + 1];

7 while (Fgets(sendline, MAXLINE, fp) != NULL) {

8 Sendto(sockfd, sendline, strlen(sendline), 0, pservaddr, servlen);

9 n = Recvfrom(sockfd, recvline, MAXLINE, 0, NULL, NULL);

10 recvline[n] = 0; /* завершающий нуль */

11 Fputs(recvline, stdout);

12 }

13 }

7-12
В цикле обработки на стороне клиента имеется четыре шага: чтение строки из стандартного потока ввода при помощи функции
fgets
, отправка строки серверу с помощью функции
sendto
, чтение отраженного ответа сервера с помощью функции
recvfrom
и помещение отраженной строки в стандартный поток вывода с помощью функции
fputs
.

Наш клиент не запрашивал у ядра присваивания динамически назначаемого порта своему сокету (тогда как для клиента TCP это имело место при вызове функции

connect
). В случае сокета UDP при первом вызове функции
sendto
ядро выбирает динамически назначаемый порт, если с этим сокетом еще не был связан никакой локальный порт. Как и в случае TCP, клиент может вызвать функцию bind явно, но это делается редко.

Обратите внимание, что при вызове функции

recvfrom
в качестве пятого и шестого аргументов задаются пустые указатели. Таким образом мы сообщаем ядру, что мы не заинтересованы в том, чтобы знать, кто отправил ответ. Существует риск, что любой процесс, находящийся как на том же узле, так и на любом другом, может отправить на IP-адрес и порт клиента дейтаграмму, которая будет прочитана клиентом, предполагающим, что это ответ сервера. Эту ситуацию мы рассмотрим в разделе 8.8.

Как и в случае функции сервера

dg_echo
, функция клиента
dg_cli
является не зависящей от протокола, но функция main клиента зависит от протокола. Функция main размещает в памяти и инициализирует структуру адреса сокета, относящегося к определенному типу протокола, а затем передает функции
dg_cli
указатель на структуру вместе с ее размером.

8.7. Потерянные дейтаграммы

Клиент и сервер UDP в нашем примере являются ненадежными. Если дейтаграмма клиента потеряна (допустим, она проигнорирована неким маршрутизатором между клиентом и сервером), клиент навсегда заблокируется в своем вызове функции

recvfrom
внутри функции
dg_cli
, ожидая от сервера ответа, который никогда не придет. Аналогично, если дейтаграмма клиента приходит к серверу, но ответ сервера потерян, клиент навсегда заблокируется в своем вызове функции
recvfrom
. Единственный способ предотвратить эту ситуацию — поместить тайм-аут в клиентский вызов функции
recvfrom
. Мы рассмотрим это в разделе 14.2.

Простое помещение тайм-аута в вызов функции

recvfrom
— еще не полное решение. Например, если заданное время ожидания истекло, а ответ не получен, мы не можем сказать точно, в чем дело — или наша дейтаграмма не дошла до сервера, или же ответ сервера не пришел обратно. Если бы запрос клиента содержал требование типа «перевести определенное количество денег со счета А на счет Б» (в отличие от случая с нашим простым эхо-сервером), то тогда между потерей запроса и потерей ответа существовала бы большая разница. Более подробно о добавлении надежности в модель клиент-сервер UDP мы расскажем в разделе 22.5.

8.8. Проверка полученного ответа

В конце раздела 8.6 мы упомянули, что любой процесс, который знает номер динамически назначаемого порта клиента, может отправлять дейтаграммы нашему клиенту, и они будут перемешаны с нормальными ответами сервера. Все, что мы можем сделать, — это изменить вызов функции

recvfrom
, представленный в листинге 8.4, так, чтобы она возвращала IP-адрес и порт отправителя ответа, и игнорировать любые дейтаграммы, приходящие не от того сервера, которому мы отправляем дейтаграмму. Однако здесь есть несколько ловушек, как мы дальше увидим.

  • Читать дальше
  • 1
  • ...
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • ...

Ебукер (ebooker) – онлайн-библиотека на русском языке. Книги доступны онлайн, без утомительной регистрации. Огромный выбор и удобный дизайн, позволяющий читать без проблем. Добавляйте сайт в закладки! Все произведения загружаются пользователями: если считаете, что ваши авторские права нарушены – используйте форму обратной связи.

Полезные ссылки

  • Моя полка

Контакты

  • chitat.ebooker@gmail.com

Подпишитесь на рассылку: