UNIX: разработка сетевых приложений - Страница 389
39 }40 }41 exit(0);42 }Эта программа корректно работает на узле с единственным IP-адресом. Если запустить программу из листинга 11.1 на узле с четырьмя IP-адресами, то получим:
freebsd % hostent cnn.comofficial hostname: cnn.comaddress: 64.236.16.20address: 64.236.16.52address: 64.236.16.84address: 64.236.16.116address: 64 236.24.4address: 64.236.24.12address: 64.236.24.20address: 64.236.24.28Но если запустить программу из листинга Д.4 на том же узле, в выводе будет только первый IP-адрес:
freebsd % hostent2 cnn.comofficial hostname: cnn.comaddress: 64.236.24.4name = www1.cnn.comПроблема заключается в том, что две функции,
gethostbynamegethostbyaddrhostentgethostbyaddrh_addr_listgethostbyname11.2. Если ваша система не поддерживает повторно входимую версию функции
gethostbyaddrgethostbyaddrgethostbyname11.3. Сервер
chargen11.4. Эта возможность поддерживается некоторыми распознавателями, но переносимая программа не может использовать ее, потому что POSIX никак ее не оговаривает. В листинге Д.5 приведена измененная версия. Порядок тестирования строки с именем узла имеет значение. Сначала мы вызываем функцию
inet_ptongethostbynameЕсли строка является допустимым IP-адресом в точечно-десятичной записи, мы создаем свой массив указателей (
addrspptrПоскольку адрес уже был переведен в двоичное представление в структуре адреса сокета, мы заменяем вызов функции
memcpymemmoveЛистинг Д.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 <hostname> <service>");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 } else22 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 else28 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 %sn",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");