Разработка приложений в среде Linux. Второе издание - Майкл Джонсон
Шрифт:
Интервал:
Закладка:
char** h_aliases; /* псевдонимы (завершающиеся NULL) */
int h_addrtype; /* тип адреса хоста */
int h_length; /* длина адреса */
char** h_addr_list; /* список адресов (завершающийся NULL) */
};
Здесь h_name — каноническое имя хоста. Массив h_aliases содержит все псевдонимы данного хоста. Последняя запись в h_aliases — это указатель NULL, сигнализирующий о конце массива.
Параметр h_addrtype сообщает тип адреса хоста. В данной главе будет применяться только AF_INET. Приложения, которые создавались для поддержки IPv6, получат и другие типы адресов[147]. Следующий член h_length указывает длину двоичных адресов для данного хоста. Для адресов AF_INET эта длина равна sizeof(struct in_addr). Последний элемент h_addr_list представляет собой массив указателей на адреса данного хоста, последний из которых равен NULL для обозначения конца списка. Если h_addrtype равен AF_INET, то каждый указатель в этом списке указывает на структуру struct in_addr.
Две библиотечные функции выполняют преобразования между IP-номерами и именами хостов. Первая из них gethostbyname() возвращает struct hostent для имени хоста. Вторая — gethostbyaddr() — возвращает информацию о машине с данным IP-адресом.
#include <netdb.h>
struct hostent * gethostbyname(const char * name);
struct hostent * gethostbyaddr(const char * addr, int len, int type);
Обе функции возвращают указатель на struct hostent. Структура может быть перезаписана при последующем вызове одной из функций, поэтому все значения, которые могут понадобиться позже, программа должна сохранять.
Функция gethostbyname() принимает один параметр — строку, содержащую имя хоста. Функция gethostbyaddr() принимает три параметра, которые вместе определяют адрес. Первый из них addr указывает на struct in_addr. Следующий len устанавливает длину информации, на которую указывает параметр addr. Последний type излагает тип адреса, который нужно преобразовать в имя хоста (AF_INET для IPv4-адресов).
Если во время поиска имени хоста происходят ошибки, то код ошибки передается в h_errno. Вызов функции herror() распечатывает описание ошибки (данная функция почти идентична стандартной функции perror()).
Единственный код ошибки, на котором тестируется большинство программ, это NETDB_INTERNAL, который указывает на неудачный системный вызов. При возвращении этой ошибки параметр errno содержит описание той проблемы, которая привела к отказу.
17.8.3. Пример поиска информации хоста с использованием унаследованных функций
Ниже приводится пример программы, использующей inet_aton(), inet_ntoa(), gethostbyname(), gethostbyaddr(). Она принимает единственный аргумент, который может быть либо именем хоста, либо IP-адресом в десятичном представлении с точками. Она отыскивает хост и распечатывает все имена хоста и IP-адреса, ассоциированные с ним.
Любой аргумент, который является действительным десятичным адресом, считается IP-номером, а не именем хоста.
1: /* lookup.с */
2:
3: /* Получает либо имя хоста, либо IP-адрес в командной строке, выводит
4: каноническое имя хоста для данного хоста и все IP-номера и имена
5: хостов, ассоциированные с ним. */
6:
7: #include <netdb.h> /* для gethostby* */
8: #include <sys/socket.h>
9: #include <netinet/in.h> /* для адресных структур */
10: #include <arpa/inet.h> /* для inet_ntoa() */
11: #include <stdio.h>
12:
13: int main(int argc, const char ** argv) {
14: struct hostent * answer;
15: struct in_addr address, ** addrptr;
16: char ** next;
17:
18: if (argc != 2) {
19: fprintf(stderr, "поддерживается только одиночный аргументn");
20: return 1;
21: }
22:
23: /* Если аргумент выглядит как IP, то принимаем его как таковой
24: и выполняет обратный поиск имени */
25: if (inet_aton(argv[1], &address))
26: answer = gethostbyaddr((char *)&address, sizeof(address),
27: AF_INET);
28: else
29: answer = gethostbyname(argv[1])
30:
31: /* поиск имени хоста не удался */
32: if (!answer) {
33: herror("ошибка поиска хоста");
34: return 1;
35: }
36:
37: printf("Каноническое имя хоста: %sn", answer->h_name);
38:
39: /* если есть псевдонимы, все они выводятся на печать */
40: if (answer->h_aliases[0]) {
41: printf("Псевдонимы:");
42: for(next = answer->h_aliases; *next; next++)
43: printf(" %s", *next);
44: printf("n");
45: }
46:
47: /* отобразить все IP-адреса для данной машины */
48: printf("Адреса:");
49: for (addrptr = (structin_addr **) answer->h_addr_list;
50: *addrptr; addrptr++)
51: printf (" %s", inet_ntoa(**addrptr));
52: printf("n");
53:
54: return 0;
55: }
Ниже показан пример вывода этой программы.
$ ./lookup ftp.netscape.com
Каноническое имя хоста: ftp25.netscape.com
Псевдонимы: ftp.netscape.com anonftp10.netscape.com
Адреса: 207.200.74.21
17.8.4. Поиск номеров портов
Новые функции getaddrinfo() и getnameinfo() предлагают простое выполнение преобразований имен служб в номера портов с одновременным определением имени хоста. В старых реализациях поиск имен служб проводился абсолютно независимо от поиска имен хостов. Доступ к именам служб можно получить через функцию getservbyname().
#include <netdb.h>
struct servent * getservbyname(const char * name,
const char * protocol);
Первый параметр name представляет собой имя службы, о которой в приложении требуется информация. Параметр protocol указывает протокол для использования. База данных служб содержит информацию о других протоколах (особенно UDP); конкретное определение протокола позволяет функции игнорировать информацию по другим протоколам. Параметр protocol обычно является строкой "tcp", хотя могут использоваться и другие имена протоколов, например, "udp".
Функция getservbyname() возвращает указатель на структуру, которая содержит информацию о запрашиваемой службе. Информация может перезаписываться при последующем вызове getservbyname(), поэтому важные данные нужно сохранять в приложении. Функция getservbyname() возвращает следующую информацию:
#include <netdb.h>
struct servent {
char * s_name; /* имя службы */
char ** s_aliases; /* псевдонимы службы */
int s_port; /* номер порта */
char * s_proto; /* протокол для использования */
}
Каждая служба может иметь несколько имен, ассоциированных с ней, но только один номер порта. Переменная s_name регистрирует каноническое имя службы, s_port содержит официальный номер порта данной службы (представленный в сетевом порядке байтов), s_proto представляет протокол для использования (например, "tcp"). Член s_aliases является массивом указателей псевдонимов службы (указатель NULL обозначает конец списка).
Если функция не выполняет свою работу, то она возвращает NULL и устанавливает h_errno. Ниже приведен пример программы, которая извлекает TCP-службу, указанную в командной строке, и выводит на экран каноническое имя, номер порта и все псевдонимы данной службы.
1: /* services.с */
2:
3: #include <netdb.h>
4: #include <netinet/in.h>
5: #include <stdio.h>
6:
7: /* Отображает номер порта TCP и все псевдонимы службы,
8: указанной в командной строке */
9:
10: /* services.с отыскивает номер порта для службы */
11: int main(int argc, const char ** argv) {
12: struct servent * service;
13: char ** ptr;
14:
15: if (argc != 2) {
16: fprintf(stderr, "поддерживается только одиночный аргументn");
17: return 1;
18: }
19:
20: /* поиск службы в /etc/services, в случае неудачи
21: передается ошибка */
22: service = getservbyname(argv[1] , "tcp");
23: if (!service) {
24: herror("getservbyname failed");
25: return 1;
26: }
27:
28: printf("служба: %sn", service->s_name);
29: printf("tcp-порт: %dn", ntohs(service->s_port));
31: /* отобразить все псевдонимы, которые имеет данная служба */
32: if (*service->s_aliases) {
33: printf("псевдонимы:");
34: for (ptr = service->s_aliases; *ptr; ptr++)