Проблема заключается в том, что две функции, gethostbyname
gethostbyaddr
, совместно используют одну и ту же структуру hostent
, как было показано в разделе 11.18. Когда наша новая программа вызывает функцию gethostbyaddr
, она повторно использует данную структуру вместе с областью памяти, на которую структура указывает (массив указателей h_addr_list
), стирая три оставшиеся IP-адреса, возвращаемые функцией gethostbyname
.11.2. Если ваша система не поддерживает повторно входимую версию функции gethostbyaddr
gethostbyaddr
, вам следует создать копию массива указателей, возвращаемых функцией gethostbyname
, и данных, на которые указывает этот массив.11.3. Сервер chargen
11.4. Эта возможность поддерживается некоторыми распознавателями, но переносимая программа не может использовать ее, потому что POSIX никак ее не оговаривает. В листинге Д.5 приведена измененная версия. Порядок тестирования строки с именем узла имеет значение. Сначала мы вызываем функцию inet_pton
gethostbyname
, которая обычно требует некоторых сетевых ресурсов и времени.Если строка является допустимым IP-адресом в точечно-десятичной записи, мы создаем свой массив указателей (addrs
pptr
.Поскольку адрес уже был переведен в двоичное представление в структуре адреса сокета, мы заменяем вызов функции memcpy
memmove
, так как при вводе IP-адреса в точечно-десятичной записи исходное и конечное поля в данном вызове одинаковые.Листинг Д.5
. Допускаем как использование IP-адреса в точечно-десятичной записи, так и задание имени узла, номера порта или имени службы//names/daytimetcpcli2.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, *addrs[2];
9 struct hostent *hp;
10 struct servent *sp;
11 if (argc != 3)
12 err_quit("usage: daytimetcpcli2
13 bzero(&servaddr, sizeof(servaddr));
14 servaddr.sin_family = AF_INET;
15 if (inet_pton(AF_INET, argv[1], &servaddr.sin_addr) == 1) {
16 addrs[0] = &servaddr.sin_addr;
17 addrs[1] = NULL;
18 pptr = &addrs[0];
19 } else if ((hp = gethostbyname(argv[1])) != NULL) {
20 pptr = (struct in_addr**)hp->h_addr_list;
21 } else
22 err_quit("hostname error for %s: %s", argv[1], hstrerror(h_errno));
23 if ((n = atoi(argv[2])) > 0)
24 servaddr.sin_port = htons(n);
25 else if ((sp = getservbyname(argv[2], "tcp")) != NULL)
26 servaddr.sin_port = sp->s_port;
27 else
28 err_quit("getservbyname error for %s", argv[2]);
29 for (; *pptr != NULL; pptr++) {
30 sockfd = Socket(AF_INET, SOCK_STREAM, 0);
31 memmove(&servaddr.sin_addr, *pptr, sizeof(struct in_addr));
32 printf("trying %s\n",
33 Sock_ntop((SA*)&servaddr, sizeof(servaddr)));
34 if (connect(sockfd, (SA*)&servaddr, sizeof(servaddr)) == 0)
35 break; /* успех */
36 err_ret("connect error");
37 close(sockfd);
38 }
39 if (*pptr == NULL)
40 err_quit("unable to connect");
41 while ((n = Read(sockfd, recvline, MAXLINE)) > 0) {