Книга: UNIX: разработка сетевых приложений
Пример: клиент времени и даты
Разделы на этой странице:
Пример: клиент времени и даты
В листинге 11.5 показан наш клиент времени и даты из листинга 1.1, переписанный с использованием функции tcp_connect
.
Листинг 11.5. Клиент времени и даты, переписанный с использованием функции tcp_connect
//names/daytimetcpcli.c
1 #include "unp.h"
2 int
3 main(int argc, char **argv)
4 {
5 int sockfd, n;
6 char recvline[MAXLINE + 1];
7 socklen_t len;
8 struct sockaddr_storage *ss;
9 if (argc != 3)
10 err_quit
11 ("usage, daytimetcpcli <hostname/IPaddress> <service/port#>");
12 sockfd = Tcp_connect(argv[1], argv[2]);
13 len = sizeof(ss);
14 Getpeername(sockfd, (SA*)&ss, &len);
15 printf("connected to %sn", Sock_ntop_host((SA*)&ss, len));
16 while ((n = Read(sockfd, recvline, MAXLINE)) > 0) {
17 recvline[n] = 0; /* завершающий нуль */
18 Fputs(recvline, stdout);
19 }
20 exit(0);
21 }
Аргументы командной строки
9-11
Теперь нам требуется второй аргумент командной строки для задания либо имени службы, либо номера порта, что позволит нашей программе соединяться с другими портами.
Соединение с сервером
12
Теперь весь код сокета для этого клиента выполняется функцией tcp_connect
.
Вывод ответа сервера
13-15
Мы вызываем функцию getpeername
, чтобы получить адрес протокола сервера и вывести его. Мы делаем это для проверки протокола, используемого в примерах, которые скоро покажем.
Обратите внимание, что функция tcp_connect
не возвращает размера структуры адреса сокета, который использовался для функции connect
. Мы могли добавить еще один аргумент-указатель, чтобы получить это значение, но при создании этой функции мы стремились добиться меньшего числа аргументов, чем у функции getaddrinfo
. Поэтому мы определяем константу MAXSOCKADDR
в нашем заголовке unp.h
так, чтобы ее размер равнялся размеру наибольшей структуры адреса сокета. Обычно это размер структуры адреса доменного сокета Unix (см. раздел 14.2), немного более 100 байт. Мы выделяем в памяти пространство для структуры указанного размера и заполняем ее с помощью функции getpeername
.
Эта версия нашего клиента работает и с IPv4, и с IPv6, тогда как версия, представленная в листинге 1.1, работала только с IPv4, а версия из листинга 1.2 — только с IPv6. Сравните нашу новую версию с представленной в листинге Д.6, которую мы написали, чтобы использовать функции gethostbyname
и getservbyname
для поддержки и IPv4, и IPv6.
Сначала мы задаем имя узла, поддерживающего только IPv4:
freebsd % daytimetcpcli linux daytime
connected to 206 168.112.96
Sun Jul 27 23:06:24 2003
Затем мы задаем имя узла, поддерживающего и IPv4, и IPv6:
freebsd % daytimetcpcli aix daytime
connected to 3ffe:b80:1f8d:2:204:acff:fe17:bf38
Sun Jul 27 23:17:13 2003
Используется адрес IPv6, поскольку у узла имеется и запись типа AAAA, и запись типа А. Кроме того, функция tcp_connect
устанавливает семейство адресов AF_UNSPEC
, поэтому, как было отмечено в табл. 11.3, сначала идет поиск записей типа AAAA, и только если этот поиск неудачен, выполняется поиск записей типа А.
В следующем примере мы указываем на необходимость использования именно адреса IPv4, задавая имя узла с суффиксом -4
, что, как мы отмечали в разделе 11.2, в соответствии с принятым нами соглашением означает имя узла, который поддерживает только записи типа А:
freebsd % daytimetcpcli aix-4 daytime
connected to 192.168.42.2
Sun Jul 27 23:17:48 2003
- 18.1. Вывод времени и даты
- 1.6. Таблица соответствия примеров технологии клиент-сервер
- Пример: аргументы типа «значение-результат»
- Пример: не зависящий от протокола UDP-клиент времени и даты
- 1.2. Простой клиент времени и даты
- Пример: сервер времени и даты с указанием протокола
- Пример установочного скрипта
- Пример из практики
- Совместимость клиентов и серверов различных версий
- Клиенты 3-го диалекта
- Аватар идеального клиента
- ПРИМЕР ПРОСТОЙ ПРОГРАММЫ НА ЯЗЫКЕ СИ