Пример: клиент времени и даты
Пример: клиент времени и даты
В листинге 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 %s ", 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
Данный текст является ознакомительным фрагментом.