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

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-адрес и порт отправителя ответа, и игнорировать любые дейтаграммы, приходящие не от того сервера, которому мы отправляем дейтаграмму. Однако здесь есть несколько ловушек, как мы дальше увидим.

Сначала мы изменяем функцию клиента main(см. листинг 8.3) для работы со стандартным эхо-сервером (см. табл. 2.1). Мы просто заменяем присваивание

servaddr.sin_port = htons(SERV_PORT);

присваиванием

servaddr.sin_port = htons(7);

Теперь мы можем использовать с нашим клиентом любой узел, на котором работает стандартный эхо-сервер.

Затем мы переписываем функцию dg_cli, с тем чтобы она размещала в памяти другую структуру адреса сокета для хранения структуры, возвращаемой функцией recvfrom. Мы показываем ее в листинге 8.5.

Листинг 8.5. Версия функции dg_cli, проверяющая возвращаемый адрес сокета

//udpcliserv/dgcliaddr.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  socklen_t len;

 8  struct sockaddr *preply_addr;


 9  preply_addr = Malloc(servlen);


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


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


12   len = servlen;

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

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

1001 совет по обустройству компьютера
1001 совет по обустройству компьютера

В книге собраны и обобщены советы по решению различных проблем, которые рано или поздно возникают при эксплуатации как экономичных нетбуков, так и современных настольных моделей. Все приведенные рецепты опробованы на практике и разбиты по темам: аппаратные средства персональных компьютеров, компьютерные сети и подключение к Интернету, установка, настройка и ремонт ОС Windows, работа в Интернете, защита от вирусов. Рассмотрены не только готовые решения внезапно возникающих проблем, но и ответы на многие вопросы, которые возникают еще до покупки компьютера. Приведен необходимый минимум технических сведений, позволяющий принять осознанное решение.Компакт-диск прилагается только к печатному изданию книги.

Юрий Всеволодович Ревич

Программирование, программы, базы данных / Интернет / Компьютерное «железо» / ОС и Сети / Программное обеспечение / Книги по IT
Access 2002: Самоучитель
Access 2002: Самоучитель

В книге рассматривается широкий круг вопросов, связанных с использованием программной среды Access 2002, которая является составной частью пакета Office 2002 и предназначена для создания банка данных в самых различных предметных областях.Подробно описывается методика проектирования объектов базы данных (таблицы, формы, отчеты, страницы доступа к данным, запросы, модули).Детально обсуждаются вопросы создания интегрированной базы данных в единой среде Access 2002: формирование БД с нуля, конвертирование в программную среду баз данных, созданных в ином программном окружении – Clarion, FoxPro.Особое внимание уделяется формированию разнообразных запросов к интегрированной базе данных Access 2002 с использованием языков программирования SQL, VBA и макросов.Приводятся общие сведения о возможностях языка обмена данными между различными компьютерами и приложениями (XML). Описываются возможности использования гиперссылок, связывающих базу данных с другими программными продуктами. Объясняется, как можно работать с базой данных Access 2002 без установки ее на компьютер, используя технологию ODBC (Open Data Base Connectivity). В приложениях приводятся количественные параметры Access 2002 и связанная с этой СУБД терминология.Предлагаемая книга будет полезна специалистам, занимающимся практической разработкой банков данных и приложений на их основе, а также студентам вузов, изучающим информатику.

Павел Юрьевич Дубнов

Программирование, программы, базы данных / ОС и Сети / Книги по IT