Страница 125 из 399
Листинг 11.2. Наш клиент времени и даты, использующий функции gethostbyname и getservbyname
//names/daytimetcpcli1.c
1 #include "unp.h"
2 int
3 main(int argc, char **argv)
4 {
5 int sockfd, n;
6 char recvline[MAXLINE + 1];
7 struct sockaddr_in servaddr;
8 struct in_addr **pptr;
9 struct in_addr *inetaddrp[2];
10 struct in_addr inetaddr;
11 struct hostent *hp;
12 struct servent *sp;
13 if (argc != 3)
14 err_quit("usage: daytimetcpcli1 <hostname> <service>");
15 if ((hp = gethostbyname(argv[1])) == NULL) {
16 if (inet_aton(argv[1], &inetaddr) == 0) {
17 err_quit("hostname error for %s: %s", argv[1],
18 hstrerror(h_errno));
19 } else {
20 inetaddrp[0] = &inetaddr;
21 inetaddrp[1] = NULL;
22 pptr = inetaddrp;
23 }
24 } else {
25 pptr = (struct in_addr**)hp->h_addr_list;
26 }
27 if ((sp = getservbyname(argv[2], "tcp")) == NULL)
28 err_quit("getservbyname error for %s", argv[2]);
29 for (; *pptr != NULL; pptr++) {
30 sockfd = Socket(AF_INET, SOCK_STREAM, 0);
31 bzero(&servaddr, sizeof(servaddr));
32 servaddr.sin_family = AF_INET;
33 servaddr.sin_port = sp->s_port;
34 memcpy(&servaddr.sin_addr, *pptr, sizeof(struct in_addr));
35 printf("trying %sn", Sock_ntop((SA*)&servaddr, sizeof(servaddr)));
36 if (co
37 break; /* успешное завершение */
38 err_ret("co
39 close(sockfd);
40 }
41 if (*pptr == NULL)
42 err_quit("unable to co
43 while ((n = Read(sockfd, recvline, MAXLINE)) > 0) {
44 recvline[n] = 0; /* null terminate */
45 Fputs(recvline, stdout);
46 }
47 exit(0);
48 }
13-28 Первый аргумент командной строки — это имя узла, передаваемое в качестве аргумента функции gethostbyname, а второй — имя службы, передаваемое в качестве аргумента функции getservbyname. Наш код подразумевает использование протокола TCP, что мы указываем во втором аргументе функции getservbyname. Если функции gethostbyname не удается найти нужное имя, мы вызываем функцию inet_aton (см. раздел 3.6), чтобы проверить, не является ли аргумент командной строки IP-адресом в формате ASCII. В этом случае формируется список из одного элемента — этого IP-адреса.
29-35 Теперь мы пишем вызовы функций socket и co
36-39 Вызывается функция co
41-42 Если цикл завершается, потому что ни один вызов функции co
43-47 Мы считываем ответ сервера и завершаем программу, когда сервер закрывает соединение.
Если мы запустим эту программу, указав один из наших узлов, на котором работает сервер времени и даты, мы получим ожидаемый результат:
freebsd % <b>daytimetcpcli1 aix daytime</b>
trying 192.168.42.2:13
Sun Jul 27 22:44:19 2003
Но еще интереснее запустить программу, обратившись к маршрутизатору с несколькими сетевыми интерфейсами, на котором не работает сервер времени и даты:
solaris % <b>daytimetcpcli1 gateway.tuc.noao.edu daytime</b>
trying 140.252.108.1:13