Литмир - Электронная Библиотека
Содержание  
A
A

char from server = В

serving client on fd 6

server waiting

removing client on fd 5

server waiting

char from server = В

removing client on fd 6

server waiting

[2]  Done  ./client3

[3]- Done  ./client3

[4]+ Done  ./client3

Для полноты аналогии, упомянутой в начале главы, в табл. 15.5 приведены параллели между соединениями на базе сокетов и телефонными переговорами.

Таблица 15.5

Телефон Сетевые сокеты
Звонок в компанию по номеру 555-0828 Подключение к IP-адресу 127.0.0.1
Ответ на звонок секретаря приемной Установка соединения с
remote host
Просьба соединить с финансовым отделом. Маршрутизация с помощью заданного порта (9734)
Ответ на звонок администратора финансового отдела Вызов
select
вернул управление серверу
Звонок переадресован свободному менеджеру по работе с корпоративными заказчиками Сервер вызывает
accept
, создавая новый сокет на добавочный номер 456

Дейтаграммы

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

Хорошим примером может служить сервис

daytime
, использованный ранее в программе getdate.c. Вы создаете сокет, выполняете соединение, читаете единственный ответ и разрываете соединение. Столько операций для простого получения даты!

Сервис

daytime
так же доступен с помощью UDP-соединений, применяющих дейтаграммы. Для того чтобы воспользоваться им, просто пошлите сервису одну дейтаграмму и получите в ответ единственную дейтаграмму, содержащую дату и время. Все просто.

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

Поскольку UDP — не дающий гарантий сервис, вы можете столкнуться с потерей вашей дейтаграммы или ответа сервера. Если данные важны для вас, возможно, придется тщательно программировать ваших UDP-клиентов, проверяя ошибки и при необходимости повторяя попытки. На практике в локальных сетях UDP-дейтаграммы очень надежны.

Для доступа к сервису, обеспечиваемому UDP-протоколом, вам следует применять системные вызовы

socket
и
close
, но вместо использования вызовов
read
и
write
для сокета вы применяете два системных вызова, характерных для дейтаграмм:
sendto
и
recvfrom
.

Далее приведена модифицированная версия программы getdate.c, которая получает дату с помощью сервиса UDP-дейтаграмм. Изменения по сравнению с предыдущей версией выделены цветом.

/* Начните с обычных include и объявлений. */

#include <sys/socket.h>

#include <netinet/in.h>

#include <netdb.h>

#include <stdio.h>

#include <unistd.h>

#include <stdlib.h>

int main(int argc, char *argv[]) {

 char *host;

 int sockfd;

 int len, result;

 struct sockaddr_in address;

 struct hostent *hostinfo;

 struct servent *servinfo;

 char buffer[128];

 if (argc == 1) host = "localhost";

 else host = argv[1];

 /* Ищет адрес хоста и сообщает об ошибке, если не находит. */

 hostinfo = gethostbyname(host);

 if (!hostinfo) {

  fprintf(stderr, "no host: %s\n", host);

  exit(1);

 }

 /* Проверяет наличие на компьютере сервиса daytime. */

<i> servinfo = getservbyname(&quot;daytime&quot;, &quot;udp&quot;);</i>

 if (!servinfo) {

  fprintf(stderr, &quot;no daytime service\n&quot;);

  exit(1);

 }

 printf(&quot;daytime port is %d\n&quot;, ntohs(servinfo-&gt;s_port));

<i> /* Создает UDP-сокет. */</i>

<i> sockfd = socket(AF_INEТ, SOCK_DGRAM, 0); </i>

<i> /* Формирует адрес для использования в вызовах sendto/recvfrom... */</i>

 address.sin_family = AF_INET;

 address.sin_port = servinfo-&gt;s_port;

 address.sin_addr = *(struct in_addr*)*hostinfo-&gt;h_addr_list;

 len = sizeof(address);

<i> result = sendto(sockfd, buffer, 1, 0, (struct sockaddr *)&amp;address, len);</i>

<i> result = recvfrom(sockfd, buffer, sizeof(buffer), 0,</i>

<i>  (struct sockaddr *)&amp;address, &amp;len);</i>

 buffer [result] = '\0';

 printf(&quot;read %d bytes: %s&quot;, result, buffer);

 close(sockfd);

277
{"b":"285844","o":1}