WinSock: Получение хоста по адресу
В недавнем примере мы делали http-запрос с помощью синхронного сокета. Мы обращались к конкретному серверу, зная его ip. Непорядок, сегодня займёмся определением ip-адреса по доменному имени, по адресу сайта.
MSDN по крайней мере предлагает нам две функции для таких операций. Первая — функция gethostbyname, вторая — функция getaddrinfo. Microsoft рекомендует использовать getaddrinfo, учитывая при том, что она появилась в winsock 2. Радует и то, что функция не зависит от протокола (будь то IPv4 или IPv6).
Структура addrinfo
Специальная структура для функции getaddrinfo. Объявим так:
paddrinfo = ^addrinfo; addrinfo = packed record ai_flags, ai_family, ai_sockettype, ai_protocol: integer; ai_addrlen: integer; ai_canonname: pchar; ai_addr: psockaddr; ai_next: paddrinfo; end;
И сразу пару переменных:
var aiHints: addrinfo; aiRes: paddrinfo;
Переменную aiHints заполним и передадим функции, таким образом мы укажем, что хотим получить в переменную aiRes, указатель на которую также передадим.
Теперь по частям:
ai_flags нам не пригодится, есть желание — читай на msdn.
ai_family, ai_sockettype, ai_protocol — это, думаю, знакомо. Семейство адресов (AF_INET мы указываем для IPv4, AF_INET6 для IPv6, также есть константы для netbios, инфракрасного порта и bluetooth адаптера), тип сокета (SOCK_STREAM для TCP протокола) и протокол (IPPROTO_TCP).
ai_addr — надеюсь, знакомая тебе структура типа sockaddr, а точнее указатель на неё. Здесь будет тот ip-адрес, который мы стремимся получить. Указатель именно на такую структуру мы передаём функции Connect, про которую можешь прочитать в предыдущем посте о том, как провести http-запрос на сокетах. ai_addrlen — размер полученной структуры ai_addr.
ai_canonname — «a canonical name for the host». У меня оно оказалось пустым.
Теперь про ai_next. «The getaddrinfo function aggregates all responses if more than one namespace provider returns information,» говорит msdn. То есть, если нам нужны другие варианты, а в данном случае они нам вряд ли нужны, то мы ходим по структурам, использую указатель ai_next, пока не наткнёмся на nil.
Функция getaddrinfo
Вот и нужная нам функция. Получение хоста может быть с помощью DNS (Domain Name System), файла hosts или других механизмов — функция не настолько низкоуровневая, то есть выдерживает все стандартные приоритеты. В стандартном модуле winsock я её не обнаружил, поэтому её нужно объявить:
function getaddrinfo(nodename, servname: PChar; hints: paddrinfo; var res: paddrinfo): integer; stdcall; external 'ws2_32.dll';
nodename — сюда пишем ‘parsers.info’, то есть доменное имя. servname — согласно msdn, название сервиса или номер порта. Подойдёт как ’80’, так и nil.
hints — наша структура aiHints. «Наставления» функции, мы указываем то, что желаем получить.
res — указатель на структуру addrinfo, в которой вдруг окажется результат.
Функция getaddrinfo в случае успешного выполнения возвращает 0, иначе — код ошибки. Например, 11001 — host not found.
Практика
Естественно, сначала нужно инициализировать winsock, про функцию WSAStartup я писал опять же здесь.
FillChar(aiHints, sizeOf(aiHints), 0); aiHints.ai_family:=AF_INET; aiHints.ai_sockettype:=SOCK_STREAM; aiHints.ai_protocol:=IPPROTO_TCP; if getaddrinfo('parsers.info', nil, @aiHints, aiRes)=0 then writeln(ord(aiRes.ai_addr.sin_addr.S_un_b.s_b1),'.', ord(aiRes.ai_addr.sin_addr.S_un_b.s_b2),'.', ord(aiRes.ai_addr.sin_addr.S_un_b.s_b3),'.', ord(aiRes.ai_addr.sin_addr.S_un_b.s_b4)) else writeln('socket error ', WSAGetLastError);
Этот нехитрый код выводит ip-адрес моего блога.
Вроде всё, кроме ссылки на скачивание работающего исходника-примера.
А тем временем Сан Саныч в своем блоге пытается облегчить жизнь программиста.
P.S. По поводу дальнейшего развития блога — планирую еще несколько постов про некоторые теоретические и практические аспекты winsock, также выложу один интересный модуль, над которым сейчас работаю. И, конечно, отчётно-обзорный пост про то, что было сделано, и про то, что планируется. Скучно не будет :)
Постовой: про запросы в интернет ты узнал, теперь узнай и про заработок в интернет
Да я тож делфи юзал да и юзаю иногда, многое очень знакомо и очень многое уже делал.
PS
Мда, действительно твоя подсветка похожа очень.
Спасибо автору, решение задачи которую я не мог решить очень долго.
Вот спасибо ;) Нужна была как раз такая функция для маленькой десктопной софтины ;))
За статью спасибо, но я сразу не разобрался.
Рекомендую Вам разместить инициализацию winsock прямо в статье, хотя бы код. Для таких как я))
Инициализация и всё остальное есть в предыдущем примере :)
Все очень легко и просто. Пример и практика в несколько раз помогли проделать урок. Спасибо.
Спасибо за примеры, и доступность. Delphi еще не умер :)
PS так увлекся, что аж 4 страницы добавил в закладки :)
Блин все наглядно и с примерами, вам бы с Андреем Галямовым познакомится, то же чел в этом деле рубит, могли бы не плохой обмен вести=)
P.S. Андрей Гаялмов это не Я=)
Федор, а кто? :D
Очень все просто получаетя когда делаешь по грамотно составленой инструкции, спасибо большое :)
Автор данной статьи так и не показал как получить запрашиваемый IP, а точнее не смог.
Об этом свидетельствует вызов функции
getaddrinfo(‘parsers.info’, nil, @aiHints, aiRes).
В коде видно, что в третий параметр передается адрес структуры addrinfo, а переменная облявлена как структура.
var
aiHints: addrinfo;
aiRes: paddrinfo;
WSAData1: TWSAData;
переменная объявлена как указатель на структуру:
function getaddrinfo(nodename, servname: PChar; hints: paddrinfo; var res: paddrinfo): integer;
stdcall; external ‘ws2_32.dll’;
да-да, спасибо)
paddrinfo = ^addrinfo;