Модераторы: Snowy, Poseidon, MetalFan
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Функция getaddrinfo, Получение IP по имени хоста 
V
    Опции темы
salik
Дата 5.3.2011, 14:28 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 74
Регистрация: 28.1.2011

Репутация: 1
Всего: 1



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

Код

procedure TForm2.Button2Click(Sender: TObject);
type

    //http://msdn.microsoft.com/en-us/library/ms737529%28v=VS.85%29.aspx
    Psockaddr = ^sockaddr;
    Paddrinfo = ^addrinfo;

    addrinfo =  record
      ai_flags     : Integer;
      ai_family    : Integer;
      ai_socktype  : Integer;
      ai_protocol  : Integer;
      ai_addrlen   : Cardinal;
      ai_canonname : PAnsiChar;
      ai_addr      : Psockaddr;
      ai_next      : ^addrinfo;
    end;


var  rez1, rez2 : Paddrinfo;
     wVersionRequested :Integer;
     lwsaData : WSAData;
     error : DWORD;
     hWs2_32 : THandle;
     getaddrinfo : function ( pNodeName : PAnsiChar;
                              pServiceName : PAnsiChar;
                              const pHints : Paddrinfo;
                              out ppResult : Paddrinfo
                             ) : DWORD; stdcall;
     freeaddrinfo : function ( ai : Paddrinfo) : DWORD; stdcall;

begin
  hWs2_32 := LoadLibraryA('Ws2_32.dll');
  getaddrinfo := GetProcAddress(hWs2_32,'getaddrinfo');
  freeaddrinfo := GetProcAddress(hWs2_32,'freeaddrinfo');
  if not (Assigned(getaddrinfo) and Assigned (freeaddrinfo)) then begin
    if hWs2_32 <> 0 then FreeLibrary(hWs2_32);
    Memo1.Lines.Add('Необходимые процедуры или функции не найдены в библиотеке Ws2_32.dll.');
     Memo1.Lines.Add(IntToStr(GetLastError));
     if hWs2_32 <> 0 then FreeLibrary(hWs2_32);
    Exit;
  end;

  try
    wVersionRequested := MakeWord(2,2);
    if (WSAStartup(wVersionRequested,lwsaData) <> 0) then
    begin
      Memo1.Lines.Add('Ошибка при вызове функции "WSAStartup".');
    end;

    rez1 := nil;
    rez2 := nil;
    if rez1 = nil then New(rez1);

    with rez1^ do begin
      ai_family := AF_INET;
      ai_socktype := SOCK_STREAM;
      ai_protocol := IPPROTO_TCP;
    end;

    error := getaddrinfo('forum.vingrad.ru',nil,rez1,rez2);

    if error = 0 then begin
      Memo1.Lines.Add(rez2^.ai_canonname);
    end;
    Memo1.Lines.Add('Код '+IntToStr(error));

  finally
    WSACleanup;
    if rez1 <> nil then begin
      Dispose(rez1);
      rez1 := nil;
    end;
    freeaddrinfo(rez2);
    if hWs2_32 <> 0 then FreeLibrary(hWs2_32);
  end;

end;

PM MAIL   Вверх
MetalFan
Дата 5.3.2011, 15:27 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Аццкий Сотона
****


Профиль
Группа: Комодератор
Сообщений: 3815
Регистрация: 2.10.2006
Где: Moscow

Репутация: 14
Всего: 128



Сначала неплохо бы сформулировать понятный другим вопрос.
Какие данные? То, что в Memo1 добавляются?
И вообще код местами бредовый написан.


--------------------
There are always someone smarter than you...
PM MAIL   Вверх
salik
Дата 5.3.2011, 16:17 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 74
Регистрация: 28.1.2011

Репутация: 1
Всего: 1



Цитата(MetalFan @ 5.3.2011,  15:27)
Сначала неплохо бы сформулировать понятный другим вопрос.
Какие данные? То, что в Memo1 добавляются?
И вообще код местами бредовый написан.

Хорошо. Я напишу как сам понимаю эту кухню, а вы меня поправьте, если не прав.

Основная задача - это определить IP по имени хоста. Функция getaddrinfo как раз этим и занимается.
После изучения MSDN пришел к следующему описанию структуры

Код

//http://msdn.microsoft.com/en-us/library/ms737529%28v=VS.85%29.aspx
    Psockaddr = ^sockaddr;
    Paddrinfo = ^addrinfo;

    addrinfo = packed record
      ai_flags     : Integer;
      ai_family    : Integer;
      ai_socktype  : Integer;
      ai_protocol  : Integer;
      ai_addrlen   : Cardinal;
      ai_canonname : PAnsiChar;
      ai_addr      : Psockaddr;
      ai_next      : ^addrinfo;
    end;


функция принимает 4 параметра. Первые два: имя хоста и имя сервиса, соответственно.
остальные два указатели на структуру addrinfo;

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

Сложность заключается в том, что я не знаком с языком C++ и приведенные примеры не дают ответы.

Проблема в том, что функция отрабатывает с ошибкой (11003). Это возможно связано с неправильным описанием структуры.
Если третий параметр задать nil, то ошибок нет, но опятьже, как мне получить IP в текстовом формате.

PM MAIL   Вверх
Snowy
Дата 5.3.2011, 16:26 (ссылка) |    (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Модератор
Сообщений: 11363
Регистрация: 13.10.2004
Где: Питер

Репутация: 53
Всего: 484



Цитата(salik @  5.3.2011,  16:17 Найти цитируемый пост)
Основная задача - это определить IP по имени хоста
gethostbyname
PM MAIL   Вверх
salik
Дата 5.3.2011, 19:53 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 74
Регистрация: 28.1.2011

Репутация: 1
Всего: 1



Цитата(Snowy @ 5.3.2011,  16:26)
gethostbyname

Эта функция уже устарела. И передовые разработчики Windows Sockets 2 рекомендуют использовать getaddrinfo.
Об этом написано на сайте Microsoft

Поймите меня правильно, надо разобраться именно со структурой и в каком виде "закинуть" в функцию параметры. Если написано, что надо определить адрес конкретной функцией, значит именно ей. 

 
Если есть что по существу, то помогите пожалуйста.
PM MAIL   Вверх
Чучмек
Дата 5.3.2011, 22:00 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


НЭТ БИЛЭТ
**


Профиль
Группа: Участник
Сообщений: 841
Регистрация: 11.5.2008
Где: СССР

Репутация: 4
Всего: 41



Заполни все поля структуры rez1
Код

rez1.ai_flags:=0;
rez1.ai_family:=af_inet;
rez1.ai_socktype:=SOCK_STREAM;
rez1.ai_protocol:=IPPROTO_TCP;
rez1.ai_addrlen:=0;
rez1.ai_canonname:=nil;
rez1.ai_addr:=nil;
rez1.ai_next:=nil;

Все поля кроме ai_flags,ai_family,ai_socktype и ai_protocol  должны содержать либо 0, либо nil 

Это сообщение отредактировал(а) Чучмек - 5.3.2011, 22:25


--------------------
умную мысль держи при себе, а дурной - поделись с другими 
PM MAIL   Вверх
Чучмек
Дата 5.3.2011, 22:41 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


НЭТ БИЛЭТ
**


Профиль
Группа: Участник
Сообщений: 841
Регистрация: 11.5.2008
Где: СССР

Репутация: 4
Всего: 41



Цитата(salik @  5.3.2011,  16:17 Найти цитируемый пост)
 но опятьже, как мне получить IP в текстовом формате


Код

type 
tm=array[0..3]of byte;
var
m:tm;
str:string;

m:=tm(rez2^.ai_addr^.sin_addr);
str:=inttostr(m[0])+'.'+inttostr(m[1])+'.'+inttostr(m[2])+'.'+inttostr(m[3]);



--------------------
умную мысль держи при себе, а дурной - поделись с другими 
PM MAIL   Вверх
salik
Дата 5.3.2011, 22:41 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 74
Регистрация: 28.1.2011

Репутация: 1
Всего: 1



Цитата(MetalFan @ 5.3.2011,  15:27)
Сначала неплохо бы сформулировать понятный другим вопрос.
Какие данные? То, что в Memo1 добавляются?
И вообще код местами бредовый написан.

А что именно бредового вы нашли в коде?


"Чучмек"  спасибо за участие.

Эта переменная (rez1) своего рода подсказка для функции. Это написано почти в самом конце комментариев к функции. 
Я так полагаю это должно ускорить вычисления.

Небольшая поправка в описании структуры. 
Оказывается указатель на тип SOCKADDR уже объявлен в модуле WinSock2 под именем LPSOCKADDR.

Немного изменив код
Код

if error = 0 then begin
      Memo1.Lines.Add('ai_family: '+ IntToStr(rez2^.ai_family));
      Memo1.Lines.Add('ai_socktype: '+ IntToStr(rez2^.ai_socktype));
      Memo1.Lines.Add('ai_addrlen: '+ IntToStr(rez2^.ai_addrlen));
      Memo1.Lines.Add('ai_canonname: '+ rez2^.ai_addr^.sa_data);
      Memo1.Lines.Add(inet_ntoa(in_addr(rez2^.ai_addr)));
      //WSAAddressToString(rez3^,DWORD(rez2.ai_addrlen),ww1,host,hlP);
    end;


получаем следующее значение поля Memo
Код

ai_family: 2
ai_socktype: 1
ai_addrlen: 16
ai_canonname: 
88.192.209.1
Код 0


Как видите адрес не правильный. Остается теперь с ним разобраться.


PM MAIL   Вверх
salik
Дата 6.3.2011, 09:16 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 74
Регистрация: 28.1.2011

Репутация: 1
Всего: 1



Задача решена.
Ниже представлен рабочий код. Не забудьте подключить модуль WinSock2.

Код

procedure TForm2.Button2Click(Sender: TObject);
type

    //http://msdn.microsoft.com/en-us/library/ms737529%28v=VS.85%29.aspx
    Paddrinfo = ^addrinfo;

    addrinfo = packed record
      ai_flags     : Integer;
      ai_family    : Integer;
      ai_socktype  : Integer;
      ai_protocol  : Integer;
      ai_addrlen   : Cardinal;
      ai_canonname : PPAnsiChar;
      ai_addr      : LPSOCKADDR;
      ai_next      : ^addrinfo;
    end;


var  rez1, rez2 : Paddrinfo;
     lwsaData : WSAData;
     error : DWORD;
     hWs2_32 : THandle;
     getaddrinfo : function ( pNodeName : PAnsiChar;
                              pServiceName : PAnsiChar;
                              const pHints : Paddrinfo;
                              out ppResult : Paddrinfo
                             ) : DWORD; stdcall;
     freeaddrinfo : function ( ai : Paddrinfo) : DWORD; stdcall;


begin
  hWs2_32 := LoadLibraryA('Ws2_32.dll');
  getaddrinfo := GetProcAddress(hWs2_32,'getaddrinfo');
  freeaddrinfo := GetProcAddress(hWs2_32,'freeaddrinfo');
  if not (Assigned(getaddrinfo) and Assigned (freeaddrinfo)) then begin
    if hWs2_32 <> 0 then FreeLibrary(hWs2_32);
     Memo1.Lines.Add('Необходимые процедуры или функции не найдены в библиотеке Ws2_32.dll.');
     Memo1.Lines.Add(IntToStr(GetLastError));
     if hWs2_32 <> 0 then FreeLibrary(hWs2_32);
    Exit;
  end;

  try
    if WSAStartup(MakeWord(2,2),lwsaData) <> 0 then
    begin
      Memo1.Lines.Add('Ошибка при вызове функции "WSAStartup".');
    end;

    rez1 := nil;
    rez2 := nil;
    if rez1 = nil then New(rez1);
    with rez1^ do begin
      ai_flags:=0;
      ai_family:=af_inet;
      ai_socktype:=SOCK_STREAM;
      ai_protocol:=IPPROTO_TCP;
      ai_addrlen:=0;
      ai_canonname:=nil;
      ai_addr:=nil;
      ai_next:=nil;
    end;

    error := getaddrinfo('forum.vingrad.ru','hostnames',rez1,rez2);

    if error = 0 then begin
      Memo1.Lines.Add('ai_family: '+ IntToStr(rez2^.ai_family));
      Memo1.Lines.Add('ai_socktype: '+ IntToStr(rez2^.ai_socktype));
      Memo1.Lines.Add('ai_addrlen: '+ IntToStr(rez2^.ai_addrlen));
      Memo1.Lines.Add('IP : '+ inet_ntoa(SOCKADDR_IN(rez2^.ai_addr^).sin_addr));
    end;
    Memo1.Lines.Add('Код '+IntToStr(error));

  finally
    WSACleanup;
    if rez1 <> nil then begin
      Dispose(rez1);
      rez1 := nil;
    end;
    if rez2 <> nil then begin
      freeaddrinfo(rez2);
      rez2 := nil;
    end;
    if hWs2_32 <> 0 then FreeLibrary(hWs2_32);
  end;

end;


Это сообщение отредактировал(а) salik - 6.3.2011, 12:10
PM MAIL   Вверх
MetalFan
Дата 9.3.2011, 15:19 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Аццкий Сотона
****


Профиль
Группа: Комодератор
Сообщений: 3815
Регистрация: 2.10.2006
Где: Moscow

Репутация: 14
Всего: 128



Цитата(salik @  5.3.2011,  22:41 Найти цитируемый пост)
А что именно бредового вы нашли в коде?

Да, есть пара замечаний по коду.
Код

...
    rez1 := nil;
    rez2 := nil;
    if rez1 = nil then New(rez1); // <========= ЗАЧЕМ эта проверка, если на две строчки выше и так rez1 = nil?
...


Код

    with rez1^ do begin
      ai_flags:=0;
      ai_family:=af_inet;
      ai_socktype:=SOCK_STREAM;
      ai_protocol:=IPPROTO_TCP;
      ai_addrlen:=0;
      ai_canonname:=nil;
      ai_addr:=nil;
      ai_next:=nil;
    end;

Зачем нужно по кускам "обнилять", если можно либо FillChar/ZeroMemory вызвать, либо сразу выделить память через AllocMem?



--------------------
There are always someone smarter than you...
PM MAIL   Вверх
salik
Дата 9.3.2011, 15:57 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 74
Регистрация: 28.1.2011

Репутация: 1
Всего: 1



Код

...
    rez1 := nil;
    rez2 := nil;
    if rez1 = nil then New(rez1); // <========= ЗАЧЕМ эта проверка, если на две строчки выше и так rez1 = nil?
...


Код

    with rez1^ do begin
      ai_flags:=0;
      ai_family:=af_inet;
      ai_socktype:=SOCK_STREAM;
      ai_protocol:=IPPROTO_TCP;
      ai_addrlen:=0;
      ai_canonname:=nil;
      ai_addr:=nil;
      ai_next:=nil;
    end;

Цитата

Зачем нужно по кускам "обнилять", если можно либо FillChar/ZeroMemory вызвать, либо сразу выделить память через AllocMem?


1) Если переменная "rez1" не будет равена "nil", то при вызове функции "new" будет ошибка. Это я использовал, чтобы подстраховаться.

2) А что касаемо заполнения, вы правы можно было вызвать сначала ZeroMemory, а потом подправить некоторые поля переменной. 
На сайте MSDN именно так и показано в примере на C++. Надо будет протестировать на досуге.


PM MAIL   Вверх
MetalFan
Дата 9.3.2011, 17:25 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Аццкий Сотона
****


Профиль
Группа: Комодератор
Сообщений: 3815
Регистрация: 2.10.2006
Где: Moscow

Репутация: 14
Всего: 128



1. бесполезная подстраховка для данного случая.
2. А можно вообще обойтись AllocMem - она сразу память "зачистит" после выделения.


--------------------
There are always someone smarter than you...
PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Delphi: Сети"
Snowy
Poseidon
MetalFan

Запрещено:

1. Публиковать ссылки на вскрытые компоненты

2. Обсуждать взлом компонентов и делится вскрытыми компонентами

  • Литературу по Дельфи обсуждаем здесь
  • Действия модераторов можно обсудить здесь
  • С просьбами о написании курсовой, реферата и т.п. обращаться сюда
  • Вопросы по реализации алгоритмов рассматриваются здесь
  • 90% ответов на свои вопросы можно найти в DRKB (Delphi Russian Knowledge Base) - крупнейшем в рунете сборнике материалов по Дельфи

Если Вам помогли и атмосфера форума Вам понравилась, то заходите к нам чаще! С уважением, Snowy, Poseidon, MetalFan.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Delphi: Сети | Следующая тема »


 




[ Время генерации скрипта: 0.0597 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.