PDA

Показать полную графическую версию : Программное получение IP из DNS


rarelang
03-07-2004, 02:09
Всем привет,

Я пишу сетевое приложение и недавно столкнулся со следующей проблемой. У меня есть следующий WinSock/BSD совместимый код:

signed int result;

#ifndef UNIX
WSADATA WSAData;

result = WSAStartup(MAKEWORD(1, 1), &WSAData);
if(result != 0)
{
ERRORLOG("Ошибка при инициализации системы WinSock");
throw (signed int) 1;
}
#endif

SMTPServer=socket(AF_INET, SOCK_STREAM, 0);

if(SMTPServer==INVALID_SOCKET)
{
ERRORLOG("Ошибка при создании socket объекта");
throw 2;
}

struct sockaddr_in SERVERAddress;

SERVERAddress.sin_family = AF_INET;
SERVERAddress.sin_addr.s_addr = inet_addr(SMTPIServerIP.c_str());
SERVERAddress.sin_port = htons(SMTPServerPort);

result=connect(SMTPServer,(struct sockaddr*)&SERVERAddress, sizeof(SERVERAddress));
if(result)
{
throw 3;
}

...

В данном фрагменте вызов inet_addr(SMTPIServerIP.c_str()) используется для превращения строки с IP адресом (объекта string с содержимым типа “127.0.0.1”) в in_addr.

Подскажите мне пожалуйста какие функции (не специфичные для Microsoft) я могу использовать для получения IP адреса из DNS имени.

Или же, подскажите мне пожалуйста как я могу настроить и создать SOCKET объект не имея IP адреса и располагая только DNS именем.

Заранее спасибо за любой ответ или ссылку на интересующий меня материал.


Исправлено: hasherfrog, 10:29 5-07-2004

BrutalBit
03-07-2004, 21:11
Функции для работы с адресами и DNS

В этом разделе мы обсудим несколько функций, без которых можно написать учебный пример, но без которых вряд ли обойдётся реальная программа. Поскольку для идентификации хостов в Internet широко используются доменные имена, мы должны изучить механизм преобразования их в IP-адреса. Кроме того мы изучим несколько удобных вспомогательных функций.

IP-адреса принято записывать в виде четырёх чисел, разделённых точками. Для преобразования адреса, записанного в таком формате, в число и наоборот используется семейство функций inet_addr, inet_aton и inet_ntoa.

#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

int inet_aton(const char *cp, struct in_addr *in_p);
unsigned long int inet_addr(const char *cp);
char *inet_ntoa(struct in_addr in);

Функция inet_addr часто используется в программах. Она принимает строку и возвращает адрес (уже с сетевым порядком следования байтов). Проблема с этой функцией состоит в том, что значение -1, возвращаемое ею в случае ошибки, является в то же время корректным адресом 255.255.255.255 (широковещательный адрес). Вот почему сейчас рекомендуется использовать более новую функцию inet_aton (Ascii TO Network). Для обратного преобразования используется функция inet_ntoa (Network TO Ascii). Обе эти функции работают с адресами в сетевом формате. Обратите внимание, что в случае ошибки они возвращают 0, а не -1.

Для преобразования доменного имени в IP-адрес используется функция gethostbyname.

#include <netdb.h>
   
struct hostent *gethostbyname(const char *name);

Эта функция получает имя хоста и возвращает указатель на структуру с его описанием. Рассмотрим эту структуру более подробно.

struct hostent {
   char    *h_name;
   char    **h_aliases;
   int     h_addrtype;
   int     h_length;
   char    **h_addr_list;
};
#define h_addr h_addr_list[0]

   * h_name. Имя хоста.
   * h_aliases. Массив строк, содержащих псевдонимы хоста. Завершается значением NULL.
   * h_addrtype. Тип адреса. Для Internet-домена - AF_INET.
   * h_length. Длина адреса в байтах.
   * h_addr_list. Массив, содержащий адреса всех сетевых интерфейсов хоста. Завершается нулём. Обратите внимание, что байты каждого адреса хранятся с сетевым порядке, поэтому htonl вызывать не нужно.

Как видим, gethostbyname возвращает достаточно полную информацию. Если нас интересует адрес хоста, мы можем выбрать его из массива h_addr_list. Часто берут самый первый адрес (как мы видели выше, для ссылки на него определён специальный макрос h_addr). Для определения имени хоста по адресу используется функция gethostbyaddr. Вместо строки она получает адрес (в виде sockaddr) и возвращает указатель на ту же самую структуру hostent. Используя эти две функции, нужно помнить, что они сообщают об ошибке не так, как остальные: вместо указателя возвращается NULL, а расширенный код ошибки записывается в глобальную переменную h_errno (а не errno). Соответственно, для вывода диагностического сообщения следует использовать herror вместо perror.
ПРЕДУПРЕЖДЕНИЕ
Следует иметь в виду, что функции gethostbyname и gethostbyaddr возвращают указатель на статическую область памяти. Это означает, что каждое новое обращение к одной из этих функций приведёт к перезаписи данных, полученных при преыдущем обращении.

В заключение рассмотрим ещё одно семейство полезных функций - gethostname, getsockname и getpeername.

#include <unistd.h>

int gethostname(char *hostname, size_t size);

Функция gethostname используется для получения имени локального хоста. Далее его можно преобразовать в адрес при помощи gethostbyname. Это даёт нам способ в любой момент программно получить адрес машины, на которой выполняется наша программа, что может быть полезным во многих случаях.

#include <sys/socket.h>

int getpeername(int sockfd, struct sockaddr *addr, int *addrlen);

Функция getpeername позволяет в любой момент узнать адрес сокета на "другом конце" соединения. Она получает дескриптор сокета, соединённого с удалённым хостом, и записывает адрес этого хоста в структуру, на которую указывает addr. Фактическое количество записанных байт помещается по адресу addrlen (не забудьте записать туда размер структуры addr до вызова getpeername). Полученный адрес при необходимости можно преобразовать в строку, используя inet_ntoa или gethostbyaddr. Функция getsockname по назначению обратна getpeername и позволяет определить адрес сокета на "нашем конце" соединения.

hasherfrog
05-07-2004, 10:48
Одна из многочисленных по форме  (но однообразных по содержанию) вариаций:
unsigned long host_resolve (char *host)
{
 struct in_addr addr;
 struct hostent *host_ent;

 addr.s_addr = inet_addr (host);
 if (addr.s_addr == -1)
   {
     host_ent = gethostbyname (host);
     if (host_ent == NULL)
       addr.s_addr = 0;
     else
       bcopy (host_ent->h_addr, (char *)&addr.s_addr, host_ent->h_length);
   }
 return addr.s_addr;
}
bcopy - аналог memcpy

Добавлено:

Кстати, в QT есть клас QDns. Он занимается созданием и обновлением в памяти dns-базы (соответствий dhs и ip адресов). Что интересно, в исходниках присутствует код для виндов (чего вообще-то не должно было бы быть). Можете посмотреть.




© OSzone.net 2001-2012