UNIX: разработка сетевых приложений
UNIX: разработка сетевых приложений читать книгу онлайн
Новое издание книги, посвященной созданию веб-серверов, клиент-серверных приложений или любого другого сетевого программного обеспечения в операционной системе UNIX, — классическое руководство по сетевым программным интерфейсам, в частности сокетам. Оно основано на трудах Уильяма Стивенса и полностью переработано и обновлено двумя ведущими экспертами по сетевому программированию. В книгу включено описание ключевых современных стандартов, реализаций и методов, она содержит большое количество иллюстрирующих примеров и может использоваться как учебник по программированию в сетях, так и в качестве справочника для опытных программистов.
Внимание! Книга может содержать контент только для совершеннолетних. Для несовершеннолетних чтение данного контента СТРОГО ЗАПРЕЩЕНО! Если в книге присутствует наличие пропаганды ЛГБТ и другого, запрещенного контента - просьба написать на почту [email protected] для удаления материала
39 }
40 }
41 exit(0);
42 }
Эта программа корректно работает на узле с единственным IP-адресом. Если запустить программу из листинга 11.1 на узле с четырьмя IP-адресами, то получим:
freebsd % <b>hostent cnn.com</b>
official hostname: cnn.com
address: 64.236.16.20
address: 64.236.16.52
address: 64.236.16.84
address: 64.236.16.116
address: 64 236.24.4
address: 64.236.24.12
address: 64.236.24.20
address: 64.236.24.28
Но если запустить программу из листинга Д.4 на том же узле, в выводе будет только первый IP-адрес:
freebsd % <b>hostent2 cnn.com</b>
official hostname: cnn.com
address: 64.236.24.4
name = www1.cnn.com
Проблема заключается в том, что две функции,
gethostbyname
gethostbyaddr
hostent
gethostbyaddr
h_addr_list
gethostbyname
11.2. Если ваша система не поддерживает повторно входимую версию функции
gethostbyaddr
gethostbyaddr
gethostbyname
11.3. Сервер
chargen
11.4. Эта возможность поддерживается некоторыми распознавателями, но переносимая программа не может использовать ее, потому что POSIX никак ее не оговаривает. В листинге Д.5 приведена измененная версия. Порядок тестирования строки с именем узла имеет значение. Сначала мы вызываем функцию
inet_pton
gethostbyname
Если строка является допустимым IP-адресом в точечно-десятичной записи, мы создаем свой массив указателей (
addrs
pptr
Поскольку адрес уже был переведен в двоичное представление в структуре адреса сокета, мы заменяем вызов функции
memcpy
memmove
Листинг Д.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 } 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 %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");