KnigaRead.com/
KnigaRead.com » Компьютеры и Интернет » Программное обеспечение » Уильям Стивенс - UNIX: разработка сетевых приложений

Уильям Стивенс - UNIX: разработка сетевых приложений

На нашем сайте KnigaRead.com Вы можете абсолютно бесплатно читать книгу онлайн Уильям Стивенс, "UNIX: разработка сетевых приложений" бесплатно, без регистрации.
Перейти на страницу:

Функция gethostbyname отличается от других функций сокетов, описанных нами, тем, что она не задает значение переменной errno, когда происходит ошибка. Вместо этого она присваивает глобальной целочисленной переменной h_errno одну из следующих констант, определяемых в заголовке <netdb.h>:

■ HOST_NOT_FOUND;

■ TRY_AGAIN;

■ NO_RECOVERY;

■ NO_DATA (идентично NO_ADDRESS).

Ошибка NO_DATA означает, что заданное имя действительно, но у него нет записи типа А. Примером может служить имя узла, имеющего только запись типа MX.

Самые современные распознаватели предоставляют функцию hstrerror, которая в качестве единственного аргумента получает значение h_errno и возвращает указатель типа const char* на описание ошибки. Некоторые примеры строк, возвращаемых этой функцией, мы увидим в следующем примере.

Пример

В листинге 11.1[1] показана простая программа, вызывающая функцию gethostbyname для любого числа аргументов командной строки и выводящая всю возвращаемую информацию.

Листинг 11.1. Вызов функции и вывод возвращаемой информации

//names/hostent.c

 1 #include "unp.h"


 2 int

 3 main(int argc, char **argv)

 4 {

 5  char *ptr, **pptr;

 6  char str[INET_ADDRSTRLEN];

 7  struct hostent *hptr;


 8  while (--argc > 0) {

 9   ptr = *++argv;

10   if ((hptr = gethostbyname(ptr)) == NULL) {

11    err_msg("gethostbyname error for host, %s: %s",

12     ptr, hstrerror(h_errno));

13    continue;

14   }

15   printf("official hostname: %sn", hptr->h_name);


16   for (pptr = hptr->h_aliases; *pptr != NULL; pptr++)

17    printf("talias: %sn", *pptr);


18   switch (hptr->h_addrtype) {

19   case AF_INET:

20    pptr = hptr->h_addr_list;

21    for (; *pptr != NULL; pptr++)

22     printf("taddress: %sn",

23    Inet_ntop(hptr->h_addrtype, *pptr, str, sizeof(str)));

24    break;


25   default:

26    err_ret("unknown address type");

27    break;

28   }

29  }

30  exit(0);

31 }

8-14 Функция gethostbyname вызывается для каждого аргумента командной строки.

15-17 Выводится каноническое имя узла, за которым идет список альтернативных имен.

18-24 Переменная pptr указывает на массив указателей на индивидуальные адреса. Для каждого адреса мы вызываем функцию inet_ntop и выводим возвращаемую строку.

Сначала мы выполняем программу с именем нашего узла aix, у которого имеется только один адрес IPv4:

freebsd % hostent aix

official hostname: aix.unpbook.com

         address:  192.168 42.2

Обратите внимание, что официальное имя узла — это FQDN. Кроме того, хотя у узла имеется адрес IPv6, возвращается только адрес IPv4. Следующим будет веб-сервер с несколькими адресами IPv4:

solaris % hostent cnn.com

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

Далее идет имя, представленное в разделе 11.2 как имя с записью типа CNAME:

solaris % hostent www

official hostname: linux.unpbook.com

         alias: www.unpbook.com

         address: 206.168.112.219

Как мы и предполагали, официальное имя узла отличается от нашего аргумента командной строки.

Чтобы увидеть строки ошибок, возвращаемые функцией hstrerror, мы сначала задаем несуществующее имя узла, а затем имя, имеющее только запись типа MX:

solaris % hostent nosuchname.invalid

gethostbyname error for host: nosuchname.invalid: Unknown host


solaris % hostent uunet.uu.net

gethostbyname error for host: uunet.uu.net: No address associated with name

11.4 Функция gethostbyaddr

Функция gethostbyaddr получает в качестве аргумента двоичный IP-адрес и пытается найти имя узла, соответствующее этому адресу. Ее действие обратно действию функции gethostbyname.

#include <netdb.h>


struct hostent *gethostbyaddr(const char *addr, size_t len, int family);

Возвращает: непустой указатель в случае успешного выполнения, -1 в случае ошибки

Эта функция возвращает указатель на ту же структуру hostent, которую мы описывали при рассмотрении функции gethostbyname. Обычно в этой структуре нас интересует поле h_name, каноническое имя узла.

Аргумент addr не относится к типу char*, но в действительности это указатель на структуру in_addr, содержащую адрес IPv4. Поле len — это длина структуры: 4 для адресов IPv4. Аргумент family будет иметь значение AF_INET.

В терминах DNS функция gethostbyaddr запрашивает у сервера имен запись типа PTR в домене in-addr.arpa.

11.5. Функции getservbyname и getservbyport

Службы, как и узлы, также часто идентифицируются по именам. Используя в нашем коде имя службы вместо номера порта, при условии, что имена служб сопоставляются номерам портов в некотором файле (обычно /etc/services), мы получаем следующее преимущество. Если этой службе будет назначен другой номер порта, то нам будет достаточно изменить одну строку в файле /etc/services, вместо того чтобы перекомпилировать все приложения. Следующая функция, getservbyname, ищет службу по ее заданному имени.

ПРИМЕЧАНИЕ

Канонический список номеров портов, назначенных определенным службам, поддерживается IANA и располагается по адресу http://www.iana.org/assignments/port-numbers (см. раздел 2.9). Файл /etc/services чаще всего содержит некоторое подмножество списка IANA.

#include <netdb.h>


struct servent *getservbyname(const char *servname, const char *protoname);

Возвращает: непустой указатель в случае успешного выполнения, NULL в случае ошибки

Функция возвращает указатель на следующую структуру:

struct servent {

 char *s_name;     /* официальное имя службы */

 char **s_aliases; /* список псевдонимов */

 int s_port;       /* номер порта, записанный в сетевом порядке байтов */

 char *s_proto;    /* протокол, который нужно использовать */

};

Имя службы servname должно быть указано обязательно. Если задан и протокол (то есть если protoname — непустой указатель), то в структуре должен быть указан совпадающий протокол. Некоторые службы Интернета позволяют использовать и TCP, и UDP (например, DNS и все службы, представленные в табл. 2.1), в то время как другие поддерживают только один протокол (протоколу FTP требуется TCP). Если аргумент protoname не задан и служба поддерживает несколько протоколов, то возвращаемый номер порта зависит от реализации. Обычно это не имеет значения, поскольку службы, поддерживающие множество протоколов, как правило, используют один и тот же номер порта для протоколов TCP и UDP, но вообще говоря это не гарантируется.

Более всего в структуре servent нас интересует поле номера порта. Поскольку номер порта возвращается в сетевом порядке байтов, мы не должны вызывать функцию htons при записи его в структуру адреса сокета.

Типичные вызовы этой функции могут быть такими:

struct servent *sptr;


sptr = getservbyname("domain", "udp"); /* DNS с использованием UDP */

sptr = getservbyname("ftp", "tcp");    /* FTP с использованием TCP */

sptr = getservbyname("ftp", NULL);     /* FTP с использованием TCP */

sptr = getservbyname("ftp", "udp");    /* этот вызов приведет к ошибке */

Поскольку протоколом FTP поддерживается только TCP, второй и третий вызовы эквивалентны, а четвертый вызов приводит к ошибке. Вот соответствующие строки из файла /etc/services:

freebsd % grep -e ^ftp -e ^domain /etc/services

ftp-data  20/tcp  #File Transfer [Default Data]

ftp       21/tcp  #File Transfer [Control]

domain    53/tcp  #Domain Name Server

domain    53/udp  #Domain Name Server

ftp-agent 574/tcp #FTP Software Agent System

ftp-agent 574/udp #FTP Software Agent System

ftps-data 989/tcp # ftp protocol, data, over TLS/SSL

ftps      990/tcp # ftp protocol, control, over TLS/SSL

Следующая функция, getservbyport, ищет службу по заданному номеру порта и (не обязательно) протоколу.

#include <netdb.h>


struct servent *getservbyport(int port, const char *protname);

Возвращает: непустой указатель в случае успешного выполнения, NULL в случае ошибки

Значение аргумента port должно быть записано в сетевом порядке байтов. Типичные примеры вызова этой функции приведены ниже:

Перейти на страницу:
Прокомментировать
Подтвердите что вы не робот:*