Разрешение доменных имён (Windows)
Участников: 2
FreeBasic :: Программирование :: Общее
Страница 1 из 1
Разрешение доменных имён (Windows)
Разрешение доменного имени — это получение его IP‐адреса. Раньше для DNS‐запросов необходимо было использовать функции inet_addr и gethostbyname. Затем информацию нужно было вручную заносить в структуру sockaddr_in и только затем использовать её.
К счастью, это больше не нужно и даже нежелательно, если нужно использовать не только IPv4, но и IPv6. Корпорация Micro$oft объявила данный метод устаревшим. В современном мире есть функция GetAddrInfoW, которая выполняет всю работу DNS‐запросов, и заполняет структуры необходимыми данными. И эта функция работает с юникодом.
Вот она (функция уже объявлена в заголовочных файлах, дополнительно объявлять её не нужно):
В функцию нужно передать три входных параметра, а она заполняет память по указателю связанным списком результатов.
Первый параметр — имя хоста (доменное имя) или IP‐адрес для соединения.
Следующий параметр — сервис, который может быть номером порта ("80") или названием сервиса ("http"). Если указать сервис, то должен находиться в списке портов IANA или в файле %WINDIR%\system32\drivers\etc\services.
Наконец, третий параметр — указатель на структуру AddrInfoW, которую нужно заполнить минимальной информацией.
Вот пример вызова функции в случае, если вы — сервер и хотите слушать сеть на порту 80 или клиент и хотите соединиться с сервером через 80‐ый порт. Этот код ничего не делает, кроме создания структур, котрые будут использоваться в дальнейшем:
Функция GetAddrInfoW возвращает 0 в случае успеха и не ноль при ошибке. Подробное описание ошибок можно найти на сайте MSDN https://msdn.microsoft.com/en-us/library/windows/desktop/ms738519%28v=vs.85%29.aspx
В ai_family назначена константа AF_UNSPEC, тем самым указывая, что всё равно, использовать ли IPv4 или IPv6. Можно устанавливать этот флаг в AF_INET или AF_INET6, если нужно указать конкретный протокол.
Так как теперь в pResult содержится связанный список всего ответа на DNS‐запрос, то нужно немедленно пройтись по нему и распечатать информацию. Этот код необходим только для вывода информации об адресе доменного имени на экран.
Теперь, когда есть вся информация, можно использовать полученные от GetAddrInfoW() результаты в других функциях, чтобы установить сетевое соединение.
После всех манипуляций необходима очистка.
К счастью, это больше не нужно и даже нежелательно, если нужно использовать не только IPv4, но и IPv6. Корпорация Micro$oft объявила данный метод устаревшим. В современном мире есть функция GetAddrInfoW, которая выполняет всю работу DNS‐запросов, и заполняет структуры необходимыми данными. И эта функция работает с юникодом.
Вот она (функция уже объявлена в заголовочных файлах, дополнительно объявлять её не нужно):
- Код:
Declare Function GetAddrInfoW( _
ByRef pNodeName As WString, _ /' например "www.example.com" или IP '/
ByRef pServiceName As WString, _ /' например "http" или номер порта '/
ByVal pHints As AddrInfoW Ptr, _ /' параметры запроса '/
ByVal ppResult As AddrInfoW Ptr Ptr _ /' результат '/
)
В функцию нужно передать три входных параметра, а она заполняет память по указателю связанным списком результатов.
Первый параметр — имя хоста (доменное имя) или IP‐адрес для соединения.
Следующий параметр — сервис, который может быть номером порта ("80") или названием сервиса ("http"). Если указать сервис, то должен находиться в списке портов IANA или в файле %WINDIR%\system32\drivers\etc\services.
Наконец, третий параметр — указатель на структуру AddrInfoW, которую нужно заполнить минимальной информацией.
Вот пример вызова функции в случае, если вы — сервер и хотите слушать сеть на порту 80 или клиент и хотите соединиться с сервером через 80‐ый порт. Этот код ничего не делает, кроме создания структур, котрые будут использоваться в дальнейшем:
- Код:
' Заголовочники
#ifndef unicode
#define unicode
#endif
#include "windows.bi"
#include once "win\winsock2.bi"
#include once "win\ws2tcpip.bi"
' Инициализация сокетов
Dim objWsaData As WSAData = Any
' Нужна версия 2.2
If WSAStartup(MAKEWORD(2, 2), @objWsaData) = NO_ERROR Then
' Параметр функции
Dim hints As AddrInfoW
With hints
' Версия протокола IP не важна
.ai_family = AF_UNSPEC ' Можно поставить AF_INET6, чтобы получить только IPv6‐адреса, или AF_INET , чтобы получить IPv4
.ai_socktype = SOCK_STREAM ' Использование протокола TCP
.ai_protocol = IPPROTO_TCP
End With
' Связанный список результата
Dim pResult As AddrInfoW Ptr
' Имя сервера в юникоде, порт, параметр функции, результат
Dim intResult As Integer = GetAddrInfoW("example.org", "80", @hints, @pResult)
If intResult = 0 Then
Print "Всё хорошо"
Else
Print "Ошибка", *gai_strerror(intResult)
End If
End If
Функция GetAddrInfoW возвращает 0 в случае успеха и не ноль при ошибке. Подробное описание ошибок можно найти на сайте MSDN https://msdn.microsoft.com/en-us/library/windows/desktop/ms738519%28v=vs.85%29.aspx
В ai_family назначена константа AF_UNSPEC, тем самым указывая, что всё равно, использовать ли IPv4 или IPv6. Можно устанавливать этот флаг в AF_INET или AF_INET6, если нужно указать конкретный протокол.
Так как теперь в pResult содержится связанный список всего ответа на DNS‐запрос, то нужно немедленно пройтись по нему и распечатать информацию. Этот код необходим только для вывода информации об адресе доменного имени на экран.
- Код:
' Узел для обхода списка
Dim pPtr As AddrInfoW Ptr = pResult
' Счётчик записей
Dim i As Integer
Dim sockaddr_ip As LPSOCKADDR = Any ' Это не нужно обнулять
Dim ipBuffer As WString*256 = Any ' Это не нужно обнулять
Dim ipBufferLength As Integer = 100
Do Until pPtr = 0
i += 1
Print "Номер записи", i
Print "Флаги", pPtr->ai_flags
Print "Семейство протоколов";
Select Case pPtr->ai_family
Case AF_UNSPEC
Print " неопределено"
Case AF_INET
Print " AF_INET (IPv4)"
' Адрес
sockaddr_ip = Cast(LPSOCKADDR, pPtr->ai_addr)
' Печатаем адрес
If WSAAddressToString(sockaddr_ip, Cast(DWORD, pPtr->ai_addrlen), 0, ipBuffer, @ipBufferLength) = 0 Then
Print "Человеческий адрес", ipBuffer
Else
Print "Ошибка", WSAGetLastError()
End If
Case AF_INET6
Print " AF_INET6 (IPv6)"
' Адрес
sockaddr_ip = Cast(LPSOCKADDR, pPtr->ai_addr)
' Печатаем адрес
If WSAAddressToString(sockaddr_ip, Cast(DWORD, pPtr->ai_addrlen), 0, ipBuffer, @ipBufferLength) = 0 Then
Print "Человеческий адрес", ipBuffer
Else
Print "Ошибка", WSAGetLastError()
End If
Case Else
Print " другое", pPtr->ai_family
End Select
Print "Тип сокета";
Select Case pPtr->ai_socktype
Case 0
Print " неопределено"
Case SOCK_STREAM
Print " SOCK_STREAM (stream)"
Case SOCK_DGRAM
Print " SOCK_DGRAM (datagram)"
Case SOCK_RAW
Print " SOCK_RAW (raw)"
Case SOCK_RDM
Print " SOCK_RDM (reliable message datagram)"
Case SOCK_SEQPACKET
Print " SOCK_SEQPACKET (pseudo-stream packet)"
Case Else
Print " другой", pPtr->ai_socktype
End Select
Print "Протокол";
Select Case pPtr->ai_protocol
Case 0
Print " не определён"
Case IPPROTO_TCP
Print " IPPROTO_TCP"
Case IPPROTO_UDP
Print " IPPROTO_UDP"
Case Else
Print " другой", pPtr->ai_protocol
End Select
Print "Длина адреса:", pPtr->ai_addrlen
Print "Каноническое имя:", pPtr->ai_canonname
Print ""
Loop
Теперь, когда есть вся информация, можно использовать полученные от GetAddrInfoW() результаты в других функциях, чтобы установить сетевое соединение.
- Код:
' Открыть сокет
' Так как указана константа AF_INET, то будем соединяться только с IPv4 адресами
' но можно указать AF_INET6, если нужны IPv6
Dim iSocket As SOCKET = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, 0, 0, WSA_FLAG_OVERLAPPED)
If iSocket <> INVALID_SOCKET Then
' Обойти список адресов и соединиться с сервером
Dim pPtr As AddrInfoW Ptr = pResult
Do Until pPtr = 0
If pPtr->ai_family = AF_INET Then
If WSAConnect(iSocket, Cast(LPSOCKADDR, pPtr->ai_addr), pPtr->ai_addrlen, 0, 0, 0, 0) <> SOCKET_ERROR Then
' Соединение было успешным
Exit Do
End If
End If
pPtr = pPtr->ai_next
Loop
End If
После всех манипуляций необходима очистка.
- Код:
' Очистка памяти от связанного списка
FreeAddrInfoW(pResult)
' Завершение работы с сокетами
WSACleanup()
Последний раз редактировалось: Замабувараев (Вс Июн 21, 2015 2:19 pm), всего редактировалось 1 раз(а) (Обоснование : Опечатки)
Re: Разрешение доменных имён (Windows)
Здорово, теперь есть уже несколько статей про сеть. Спасибо!
trew- Сообщения : 331
Дата регистрации : 2010-10-14
FreeBasic :: Программирование :: Общее
Страница 1 из 1
Права доступа к этому форуму:
Вы не можете отвечать на сообщения
|
|