Книга: UNIX: разработка сетевых приложений
Пример: использование функций gethostbyname и getservbyname
Разделы на этой странице:
Пример: использование функций gethostbyname и getservbyname
Теперь мы можем изменить код нашего TCP-клиента времени и даты, показанный в листинге 1.1, так, чтобы использовать функции gethostbyname
и getservbyname
и принимать два аргумента командной строки: имя узла и имя службы. Наша программа показана в листинге 11.2. Эта программа также демонстрирует желательное поведение при установлении соединения со всеми IP-адресами сервера на узле, имеющем несколько сетевых интерфейсов: попытки продолжаются до тех пор, пока соединение не будет успешно установлено или пока не будут перебраны все адреса.
Листинг 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 (connect(sockfd, (SA*)&servaddr, sizeof(servaddr)) == 0)
37 break; /* успешное завершение */
38 err_ret("connect error");
39 close(sockfd);
40 }
41 if (*pptr == NULL)
42 err_quit("unable to connect");
43 while ((n = Read(sockfd, recvline, MAXLINE)) > 0) {
44 recvline[n] = 0; /* null terminate */
45 Fputs(recvline, stdout);
46 }
47 exit(0);
48 }
Вызов функций gethostbyname и getservbyname
13-28
Первый аргумент командной строки — это имя узла, передаваемое в качестве аргумента функции gethostbyname
, а второй — имя службы, передаваемое в качестве аргумента функции getservbyname
. Наш код подразумевает использование протокола TCP, что мы указываем во втором аргументе функции getservbyname
. Если функции gethostbyname
не удается найти нужное имя, мы вызываем функцию inet_aton
(см. раздел 3.6), чтобы проверить, не является ли аргумент командной строки IP-адресом в формате ASCII. В этом случае формируется список из одного элемента — этого IP-адреса.
Перебор всех адресов
29-35
Теперь мы пишем вызовы функций socket
и connect
в цикле, который выполняется для каждого адреса сервера, пока попытка вызова функции connect
не окажется успешной или пока не закончится список серверов. После вызова функции socket
мы заполняем структуру адреса сокета Интернета IP-адресом и номером порта сервера. Хотя в целях увеличения производительности мы могли бы вынести из цикла вызов функции bzero
и последующие два присваивания, наш код легче читать в таком виде, как он представлен сейчас. Установление соединения с сервером редко является основным источником проблем с производительностью сетевого клиента.
Вызов функции connect
36-39
Вызывается функция connect
, и если вызов оказывается успешным, функция break
завершает цикл. Если установить соединение не удается, мы выводим сообщение об ошибке и закрываем сокет. Вспомните, что дескриптор, для которого вызов функции connect
оказался неудачным, не может больше использоваться и должен быть закрыт.
Завершение программы
41-42
Если цикл завершается, потому что ни один вызов функции connect
не закончился успехом, программа завершает работу.
Чтение ответа сервера
43-47
Мы считываем ответ сервера и завершаем программу, когда сервер закрывает соединение.
Если мы запустим эту программу, указав один из наших узлов, на котором работает сервер времени и даты, мы получим ожидаемый результат:
freebsd % daytimetcpcli1 aix daytime
trying 192.168.42.2:13
Sun Jul 27 22:44:19 2003
Но еще интереснее запустить программу, обратившись к маршрутизатору с несколькими сетевыми интерфейсами, на котором не работает сервер времени и даты:
solaris % daytimetcpcli1 gateway.tuc.noao.edu daytime
trying 140.252.108.1:13
connect error: Operation timed out
trying 140.252.1.4:13
connect error: Operation timed out
trying 140.252.104.1:13
connect error: Connection refused
unable to connect
- 11.5. Функции getservbyname и getservbyport
- Пример установочного скрипта
- Пример из практики
- Восстановление с использованием инструмента gbak
- Типы страниц и их использование
- ПРИМЕР ПРОСТОЙ ПРОГРАММЫ НА ЯЗЫКЕ СИ
- Использование констант
- Использование переменной окружения ISC_PATH
- Использование сервера Yaffil внутри процесса
- Использование CAST() с типами дата
- Примеры получения статистики
- Пример применения метода «пять почему»