Чтение онлайн

ЖАНРЫ

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

12 listenfd = Tcp_listen(NULL, argv[1], &addrlen);

13 else if (argc == 3)

14 listenfd = Tcp_listen(argv[1], argv[2], &addrlen);

15 else

16 err_quit("usage; daytimetcpsrv2 [ <host> ] <service or port>");

17 for (;;) {

18 len = sizeof(cliaddr);

19 connfd = Accept(listenfd, (SA*)&cliaddr, &len);

20 printf("connection from %s\n", Sock_ntop((SA*)&cliaddr, len));

21 ticks = time(NULL);

21 snprintf(buff, sizeof(buff), "%.24s\r\n", ctime(&ticks));

23 Write(connfd, buff, strlen(buff));

24 Close(connfd);

25 }

26 }

Обработка
аргументов командной строки

11-16
Единственное изменение по сравнению с листингом 11.6 — это обработка аргументов командной строки, позволяющая пользователю в дополнение к имени службы или порту задавать либо имя узла, либо IP-адрес для связывания с сервером.

Сначала мы запускаем этот сервер с сокетом IPv4 и затем соединяемся с сервером от клиентов на двух различных узлах, расположенных в локальной подсети:

freebsd % daytimetcpsrv2 0.0.0.0 9999

connection from 192.168.42.2:32961

connection from 192.168.42.2:1389

А теперь мы запустим сервер с сокетом IPv6:

solaris % daytimetcpsrv2 0::0 9999

connection from [3ffe:b80:1f8d:2:204:acff:fe17:bf38]:32964

connection from [3ffe:b80:1f8d:2:230:65ff:fe15:caa7]:49601

connection from [::ffff:192:168:42:3]:32967

connection from [::ffff:192:168:42:3]:49602

Первое соединение — от узла

aix
, использующего IPv6, а второе — от узла
macosx
, использующего IPv6. Два следующих соединения — от узлов
aix
и
macosx
, но они используют IPv4, а не IPv6. Мы можем определить это, потому что оба адреса клиента, возвращаемые функцией
accept
, являются адресами IPv4, преобразованными к виду IPv6.

Мы только что показали, что сервер IPv6, работающий на узле с двойным стеком, может обрабатывать как клиенты IPv4, так и клиенты IPv6. Адреса IPv4-клиента передаются серверу IPv6 как адреса IPv4, преобразованные к виду IPv6, что мы рассматривали в разделе 12.2.

11.14. Функция udp_client

Наши функции, предоставляющие более простой интерфейс для функции

getaddrinfo
, в случае UDP изменяются: в этом разделе мы представляем клиентскую функцию, создающую неприсоединенный сокет UDP, а в следующем — другую функцию, создающую присоединенный сокет UDP.

#include "unp.h"

int udp_client(const char * hostname, const char * service,

void ** saptr, socklen_t * lenp);

Возвращает: дескриптор неприсоединенного сокета в случае успешного выполнения, в случае ошибки не возвращает ничего

Эта функция создает неприсоединенный сокет UDP, возвращая три элемента. Во-первых, возвращаемое значение функции — это дескриптор сокета. Во-вторых,

saptr
— это адрес указателя (объявляемого вызывающим процессом) на
структуру адреса сокета (которая динамически размещается в памяти функцией
udp_client
), и в этой структуре функция хранит IP-адрес получателя и номер порта для будущих вызовов функции
sendto
. Размер этой структуры адреса сокета возвращается как значение переменной, на которую указывает
lenp
. Последний аргумент не может быть пустым указателем (как это допустимо для последнего аргумента функции
tcp_listen
), поскольку длина структуры адреса сокета требуется в любых вызовах функций
sendto
и
recvfrom
.

В листинге 11.9 показан исходный код для этой функции.

Листинг 11.9. Функция udp_client: создание неприсоединенного сокета UDP

//lib/udp_client.c

1 #include "unp.h"

2 int

3 udp_client(const char *host, const char *serv, void **saptr, socklen_t *lenp)

4 {

5 int sockfd, n;

6 struct addrinfo hints, *res, *ressave;

7 bzero(&hints, sizeof(struct addrinfo));

8 hints.ai_family = AF_UNSPEC;

9 hints.ai_socktype = SOCK_DGRAM;

10 if ((n = getaddrinfo(host, serv, &hints, &res)) != 0)

11 err_quit("udp_client error for %s, %s: %s",

12 host, serv, gai_strerror(n));

13 ressave = res;

14 do {

15 sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);

16 if (sockfd >= 0)

17 break; /* успех */

18 } while ((res = res->ai_next) != NULL);

19 if (res == NULL) /* значение errno устанавливается при последнем

вызове функции socket */

20 err_sys("udp_client error for %s, %s", host, serv);

21 *saptr = Malloc(res->ai_addrlen);

22 memcpy(*saptr, res->ai_addr, res->ai_addrlen);

23 *lenp = res->ai_addrlen;

24 freeaddrinfo(ressave);

25 return (sockfd);

26 }

Функция

getaddrinfo
преобразует аргументы
hostname
и
service
. Создается дейтаграммный сокет. Выделяется память для одной структуры адреса сокета, и структура адреса сокета, соответствующая созданному сокету, копируется в память.

Пример: не зависящий от протокола UDP-клиент времени и даты

Теперь мы перепишем наш клиент времени и даты, показанный в листинге 11.3, так, чтобы в нем использовалась наша функция

udp_client
. В листинге 11.10 представлен не зависящий от протокола исходный код.

Листинг 11.10. UDP-клиент времени и даты, использующий нашу функцию udp_client

//names/daytimeudpcli1.c

1 #include "unp.h"

Поделиться с друзьями: