Какой у тебя адрес?
Преобразование имени хоста является самой распространенной операцией, выполняемой Winsock-приложениями в режиме блокировки. В данном случае «режим блокировки» означает, что приложение ожидает ответа от удаленного компьютера — ответа, который может никогда не прийти. До получения ответа заблокированное приложение не может продолжать работу или реагировать на ввод информации пользователем и часто кажется «мертвым».
В таких операционных системах, как Unix, Windows 95 и Windows NT, такое поведение не представляет особых проблем. Даже если приложение заблокировано, использованный в них принцип вытеснения задач позволяет другим приложениям нормально работать.
Чтобы пользователь не терял возможности взаимодействовать с любым приложением Winsock во время блокировки, Winsock заменяет блокирующие функции псевдоблокирующими асинхронными эквивалентами. Вместо того чтобы осуществлять полноценную блокировку, эти функции при ожидании завершения сетевого события переходят в цикл опроса. Псевдоблокирующие функции можно узнать по префиксу WSAAsync. Например, функция WSAAsyncGet HostByName является асинхронной версией gethostbyname. Используя WSAAsyncGet HostByName, пользователь может в любой момент прервать операцию просмотра. В блокирующих функциях такая возможность отсутствует.
Чтобы изменить поведение RESOLVER32, достаточно сменить значение свойства Access c Blocking на NonBlocking, или наоборот. Значение NonBlocking сообщает CsSocket о том, что для просмотра должны использоваться асинхронные функции.
Обычно хост Internet идентифицируется в сети по уникальному адресу
в виде четверки десятичных чисел, разделенных точками, — например, 127.0.0.1 (обратите внимание на этот специальный адрес обратной связи, с его помощью можно тестировать приложения Winsock на компьютерах, не подключенных к сети). Хотя такие адреса исключительно удобны для компьютеров, на людей они производят угнетающее впечатление. Чтобы уладить эту проблему, была разработана система, которая позволяет задать уникальное символьное имя для каждого IP-адреса. Например, имя slipper109.iaccess.za соответствует IP-адресу 196.7.7.109.
Чтобы преобразовать имя хоста, введите его в текстовом поле edHostName программы RESOLVER32. После нажатия кнопки Resolve RESOLVER32 присваивает имя, введенное в edHostName, свойству Hostname. При этом свойство вызывает метод TCsSocket.SetRemoteHostName. Если строка NameReqd пуста, SetRemote HostName сообщает об ошибке и завершается. В противном случае CsSocket проверяет значение поля FAccess (которое может быть равно Blocking или NonBlocking в зависимости от свойства Access), чтобы определить режим преобразования имени хоста в IP-адрес. Если значение FAccess равно NonBlocking, вызывается SetAsyncHostName. В противном случае функция StrpCopy преобразует FRemoteName из строки Паскаля в строку с нуль-терминатором. В листинге 5.7 показано, как это делается в CsSocket.
Листинг 5.7. Метод TCsSocket.SetRemoteHostName — преобразование
имени хоста в IP-адрес
Затем метод SetRemoteHostName с помощью функции inet_addr проверяет, не содержит ли исходная строка числового IP-адреса. Если не содержит, метод предполагает, что в ней находится имя хоста, и вызывает функцию gethostbyname для преобразования его в IP-адрес. Если имя хоста отсутствует в локальном файле хостов, gethostbyname ищет имя в удаленном файле хостов, хранящемся в сети.
Если имя не найдено, процесс поиска прекращает работу по тайм-ауту и присваивает protected-свойству FHost (которое представляет собой указатель на структуру pHostent) значение NIL. Затем SetRemoteHostName вызывает обработчик события LookUpEvent, чтобы сообщить о неудачном завершении просмотра, присваивает флагу FStatus значение Failure и возвращает управление вызывающему приложению. При удачном завершении поиска функция gethostbyname возвращает указатель на FHost, где содержится найденный адрес. Наконец, SetRemoteHostName возвращает IP-адрес в виде строки Паскаля, для чего используется следующий оператор:
FRemoteName := StrPas(inet_ntoa(FSockAddress.sin_addr));
Функция inet_itoa переводит возвращаемый IP-адрес в строку с нуль-терминатором, а функция StrPas завершает преобразование в строку Паскаля. Адресная информация сокета размещается в поле FSockAddress, откуда она позднее извлекается для установки соединения с хостом. Полученный в результате поиска IP-адрес помещается в текстовое поле edIPName (см. рис. 5.4). Для этого RESOLVER32 использует обработчик события OnLookUp, который вызывается внутри процедуры LookUpEvent. В листинге 5.8 показано, как это делается.
Рис. 5.4. RESOLVER32 после преобразования имени хоста
Листинг 5.8. Метод TfrmMain.CsSocket1Lookup, используемый
программой RESOLVER32 для отображения результатов,
полученных от функции просмотра