ПРОГРАММИРОВАНИЕ    НА    V I S U A L   C + +
РАССЫЛКА САЙТА       
RSDN.RU  

    Выпуск No. 78 от 2 июня 2002 г.

РАССЫЛКА ЯВЛЯЕТСЯ ЧАСТЬЮ ПРОЕКТА RSDN , НА САЙТЕ КОТОРОГО ВСЕГДА МОЖНО НАЙТИ ВСЮ НЕОБХОДИМУЮ РАЗРАБОТЧИКУ ИНФОРМАЦИЮ, СТАТЬИ, ФОРУМЫ, РЕСУРСЫ, ПОЛНЫЙ АРХИВ ПРЕДЫДУЩИХ ВЫПУСКОВ РАССЫЛКИ И МНОГОЕ ДРУГОЕ.

Здравствуйте, дорогие читатели рассылки!


 CТАТЬЯ

Internet API. Как и где его использовать.

Автор: Robert Coleridge
Перевод: Александр Лозовюк
Источник: Microsoft Developer Network Technology Group. Июль, 1996
netget.rar - 17 KB
Аннотация

Эта статья обсуждает общие положения работы с Internet application programming interface (API), а затем подробнее рассматривает некоторые из функций, которые могу заинтересовать всех, кто пишет интернет-броузеры или другие приложения, взаимодействующие с Internet. Использую эти функции, например InternetOpen, InternetOpenUrl, InternetReadFile или InternetCloseHandle, вы можете легко написать ряд полезных и интересных Интернет-утилит.

Win32® Internet functions ("WinInet" для краткости) экспортируются библиотекой WININET.DLL. Функции описаны в ActiveXT Software Development Kit (SDK), раздел Win32 Internet Programmer's Reference или в Win32 SDK. Для разработки приложений вам понадобится Microsoft® Visual C++® 4.0 или выше.

Введение

Программирование для Internet обычно требует знания различных протоколов, в частности TCP/IP, понимание, что такое socket и других "премудростей". К счастью для большинства из нас, такое положение дел уже исправлено. Разрабатывать приложения, использующие Internet теперь легко и безболезненно. В этом нам помогает набор функций API, известные как WinINet Software Development Kit (SDK). Эти функции, скрывая от нас большинство низкоуровневых "технических" деталей и делают программирование более легким и удобным. То, что раньше создавалось за несколько дней, теперь потребует всего несколько часов. Хотя для использования API некоторый уровень знаний все равно нужно иметь, но теперь разработка Internet-приложений стала намного легче.

WinINet SDK в настоящее время включает четыре взаимосвязанные группы функций: общие Internet URL функции, FTP функции, HTTP функции, и Gopher функции. Ряд функций в пределах каждой группы немного перекрываются, но с такой внушительной мощью весь мир буквально сосредоточен на кончике ваших пальцев!

Общий обзор Internet API

Internet API обеспечивает доступ к общим функциям URL и протокол-зависимым функциям для работы с HTTP, FTP, Gopher.

Общие URL функции

Первая группа функций более общая или универсальная и позволяет вам работать через HTTP, FTP, Gopher использую URL. Используя эту группу функций, для доступа к информации в Internet требуется три простых шага. Сначала вы получаете дескриптор определенного ресурса (который определяется через URL), потом, используя другую функцию, вы читаете содержимое файла, и, наконец, закрывает соединение, освобождая дескриптор. Что может быть проще? Все это возможно без подробного знания того, как эти функции работают на низком уровне.

Эта группа позволяет работать с ресурсами, определенными URL как с локальными файлами.

HTTP, FTP, функции для работы через Gopher

Следующие три группы функций сгруппированы вместе, хоть и обслуживают разные протоколы. В настоящее время имеются функции для поддержки HTTP, FTP и Gopher. Каждая группа имеет дело со специальными сообщениями своего протокола на более глубоком уровне и предоставляет более общие возможности, чем первая группа функций.

Каждая из этих протокол-зависимых групп функций использует некоторые общие функции, например, каждая из них использует InternetConnect для инициализации сетевого соединения. Все же каждая группа имеет функции, которые ориентированы каждая на свой протокол. Например, функции FTP позволяют вам манипулировать каталогами, что невозможно реализовать через HTTP. Рассмотрение специальных функций для каждого из протоколов находиться вне темы этой статьи. Для всестороннего ознакомления с функциями можно использовать "Microsoft Win32 Internet Programmer's Reference".

Некоторые специальные функции Internet API

Следующие разделы обсуждают некоторые функции Internet API, которые являются более общими или универсальными. Я выбрал те, которые наиболее часто используются в приложениях для работы с Internet, вне зависимости от конкретной специфики приложения. Что бы использовать эти функции, нужно иметь Microsoft Internet Explorer. Этот агент или броузер фактически обеспечивает непосредственный доступ в Internet, проверку и т.д.

InternetOpen

Для большинства приложений перед использованием любых функций Internet API нужно вызвать функцию InternetOpen. Она определяет, какая программа запрашивает доступ (прим. перев. Заполняется переменная user_agent в заголовке HTTP), нужный вам тип доступа, а также ряд необязательных параметров и возвращает вам дескриптор соединения. Теперь при каждом вызове других функций, первым передаваемым параметром будет именно этот дескриптор. Когда работа с соединением закончена, вы должны закрыть его, освободив дескриптор вызовом функции InternetCloseHandle. Например:


HINTERNET hInternetSession;   
hInternetSession = InternetOpen(
                               "Microsoft Internet Explorer",  // agent
                               INTERNET_OPEN_TYPE_PRECONFIG,   // access
                               NULL, NULL, 0);                 // defaults
.
.
.
InternetCloseHandle(hInternetSession);

Этот пример демонстрирует подключение к Internet как , и возвращает дескриптор сессии, если подключение произошло успешно. Определяя параметр INTERNET_OPEN_TYPE_PRECONFIG, вы указываете на то, что надо использовать параметры, определенные в системном реестре. Остальная часть параметров установлена как параметры по умолчанию. Теперь вы можете используя нужные вам функции, вызывая их с дескриптором hInternetSession и свободно пользоваться всеми возможностями Internet!

InternetOpenUrl

Имея дескриптор сессии, установленной функцией InternetOpen вы можете обращаться к информации в Internet используя функцию InternetOpenUrl. Эта функция позволяет вам обратиться к конкретному файлу, используя для указания его месторасположения URL. InternetOpenUrl работает независимо от протокола - будь то HTTP, FTP или Gopher. Получая дескриптор, полученный в результате вызова InternetOpen, URL и несколько необязательных параметров, эта функция возвращает вам дескриптор файла. Когда работа закончена, вы должны закрыть дескриптор, вызвав снова функцию InternetCloseHandle и передав ей результат вызова InternetOpenUrl. Теперь вы можете делать с файлом все, что хотите, конечно, если у вас есть разрешения на все те действия, которые вы собираетесь совершить. Например, чтобы обратиться к странице сайта http://www.acompany.com/welcome.htm вы просто делаете следующее:


HINTERNET hURL;
HINTERNET hInternetSession;
.
.
.
hURL = InternetOpenUrl(
         hInternetSession,               // session handle
         "http://www.acompany.com/welcome.htm",   // URL to access
         NULL, 0, 0, 0);                 // defaults
.
.
.
InternetCloseHandle(hURL);

Конечно, этот пример предполагает, что вы получили дескриптор hInternetSession прежде, чем сделали вызов InternetOpenUrl.

InternetReadFile

Функция InternetReadFile используется для непосредственной загрузки содержимого удаленного файла в память. Делается это просто: функции передается дескриптор к URL (полученный от предыдущего вызова InternetOpenUrl), указатель на буфер, куда заносятся данные и размер буфера. Пример показывает, как считать первые 1024 байта страницы в память:


BOOL bResult;
char cBuffer[1024];          // I'm only going to access 1K of info.
DWORD dwBytesRead;
HINTERNET hURL;

.
.
.
bResult = InternetReadFile(
            hURL,            // handle to URL
            (LPSTR)cBuffer,  // pointer to buffer
            (DWORD)1024,     // size of buffer
            &dwBytesRead);   // pointer to var to hold return value

Этот пример читает информацию, указанную дескриптором hURL, сохраняет ее в буфере cBuffer и устанавливает значение переменной dwBytesRead равным числу байт, которые сохранены в буфере. Это - все, что нужно для того, что бы получить нужную вам информацию из Internet. Пример также предполагает, что вы получите всю нужную информацию одним запросом, если это не так, просто повторите запрос, пока вся нужная вам информация не будет загружена. Можно сразу установить размер буфера таким, что бы он вмещал то количество данных, которое нужно, но в большинстве случаев заранее неизвестно, какого размера окажется тот файл, который вы запрашиваете.

Если функция возвращает TRUE и количество бит для чтения равно 0, значит загрузка закончена и данных больше нет. Тот же эффект будет, когда достигнут конец файла. Обязательно нужно вызвать функцию InternetCloseHandle когда работа с файлом закончена.

InternetCloseHandle

Функция InternetCloseHandle - эквивалент Win32 API CloseHandle функции. Она используется, чтобы завершить установленное подключение, которое может быть инициализировано как InternetOpenUrl, так и InternetOpen или другими функциями.


HINTERNET hURL;
.
.
.
InternetCloseHandle(hURL);

Обязательно закрывайте соединение, когда больше не используете его!

Все вместе

Допустим, вам нужно просто прочитать определенный файл (URL). Тогда ваш код может напоминать этот:


HINTERNET hInternetSession;   
HINTERNET hURL;
char cBuffer[1024];            // I'm only going to access 1K of info.
BOOL bResult;
DWORD dwBytesRead;

// Make internet connection.
hInternetSession = InternetOpen(
                  "Microsoft Internet Explorer", // agent
                  INTERNET_OPEN_TYPE_PRECONFIG,  // access
                  NULL, NULL, 0);                // defaults

// Make connection to desired page.
hURL = InternetOpenUrl(
         hInternetSession,                       // session handle
         "http://www.acompany.com/welcome.htm",  // URL to access
         NULL, 0, 0, 0);                         // defaults

// Read page into memory buffer.
bResult = InternetReadFile(
            hURL,              // handle to URL
            (LPSTR)cBuffer,    // pointer to buffer
            (DWORD)1024,       // size of buffer
            &dwBytesRead); // pointer to var to hold return value

// Close down connections.
InternetCloseHandle(hURL);
InternetCloseHandle(hInternetSession);

Это - все, что требуется для подключения, чтения определенной информации (файла) по URL и отсоединения. Как уже говорилось в начале статьи - это очень просто реализовать, не так ли?

Что с этим можно сделать?

Используя только несколько функций Internet API я покажу вам как написать консольное приложение которое "reach out and touch someone". Это приложение, которое я назвал NetGet, позволит вам загрузить информацию из Internet (страницу, файл или другие данные) и сохранить ее на локальной машине. Используя функции Internet API, обсужденные в этой статьи и некоторые другие, вы будете получать информацию с одного или нескольких URL, анализировать тэги HTML на страницах, и извлекать связанные файлы.

В действительности, вы будете писать ваше собственное приложение для вытаскивания информации из Internet. Я предупреждаю: загрузка большого файла или страницы, которая имеет много графики, может приводить к заполнению вашего жесткого диска. Не говорите, что я не предупреждал вас! Давайте исследуем основу программы - процесс загрузки файла на диск.

Загрузка одной страницы

Эта процедура самая простая. Вы сначала подключаетесь к Internet через InternetOpen, а затем подключаетесь к нужному URL с помощью InternetOpenUrl. Получив дескриптор, вызываем InternetReadFile. Как только информация скачана и находится в памяти, вы просто записываете данные на ваш локальный жесткий диск.

Следующий пример предполагает, что вы загружаете только маленькие файлы (1024 байта). Ради краткости, некоторые параметры не заполнены.


BOOL GetURLPageAndStoreToDisk(LPSTR pURLPage, LPSTR pOutputFile)
{
HINTERNET hSession;   
HINTERNET hURL;
char cBuffer[1024];      // Assume small page for sample.
BOOL bResult;
DWORD dwBytesRead;
HANDLE hOutputFile;

// Make internet connection.
hSession = InternetOpen("Microsoft Internet Explorer", . . .

// make connection to desired page
hURL = InternetOpenUrl(hSession, pURLPage, . . .

// read page into memory buffer
bResult = InternetReadFile(hURL, (LPSTR)cBuffer,
            (DWORD)1024, &dwBytesRead);

// close down connections
InternetCloseHandle(hURL);
InternetCloseHandle(hInternetSession);

// create output file
hOutputFile = CreateFile)pOutputFile, . . .

// write out data
bResult = WriteFile(hOutputFile, cBuffer, . . .

// close down file
CloseHandle(hOutputFile);

// return success
return(TRUE);
}

Загрузка связанных страниц

Теперь, когда вы увидели, как загрузить один файл, загрузить связанные файлы не составит труда - просто многократно повторить запрос, каждый с различным URL. Например:


GetURLPageAndStoreToDisk(
   "HTTP://WWW.SOMESITE.COM/INTERESTING.HTM",
   "C:\\PAGES\\INTEREST.HTM");
GetURLPageAndStoreToDisk(
   "HTTP://WWW.OTHERSITE.COM/COOL.GIF",
   "C:\\PAGES\\COOL.GIF");
etc.

Примечание. Использование двойной наклонной черты () в коде выше имеет отношение к C/C ++ синтаксису. Может в другом языке потребуется лишь один символ (подробнее смотрите руководство по конкретному языку программирования).

Синтаксический анализ тэгов HTML

Синтаксический анализ данных HTML - наиболее интересный момент работы этого приложения. HTML - тэгооснованный язык. Что я подразумеваю под "тэгооснованный язык"? Давайте исследовать строку HTML.


<a href="menu.htm"><img src="img/blue-icon.gif" border="0"></a>

Имеются два набора тэгов в строке. Есть "<а href... >: </a>" который окружает тэг "< img... >". Оба эти тэга содержат URL. "< а href " тэг содержит "menu.htm", и "<img " содержит "img/blue-icon.gif". Эти URL - относительно, страницы, в которой они содержатся. Их можно так же свободно использовать, как и, например, "http://www.home.com/welcome.htm", который является абсолютным URL.

Трудность в синтаксическом анализе тэгов выливается в два различных запроса. Первый запрос определяет, является ли URL относительным или абсолютным. Второй запрос пытается определить, является ли ссылка такой, которая нас интересует, или она ненужная для нашего приложения (прим. перев: Имеется в виду, что файл, который находиться по этой ссылке, нам не нужен, так если мы хотим сохранить страницу вместе с изображениями, то все ссылки на другие html-страницы нас не интересуют). Для этого приложения я написал простой файл данных, который содержит список уместных тегов. Этот файл можно изменять и дополнять в любое время, приспосабливая его под нужды вашего конкретного приложения.

Пожалуйста, обратите внимание, что не все страницы могут быть загружены. Например, .ASP файл имеет атрибут "только на выполнение" и не может быть прочитан непосредственно. Поэтому я написал специальный файл, в котором перечислены те расширения, которые возможно загрузить.

Программа NetGet

Используя вышеописанные функции, и пару других, не описанных в статье, я создал приложение для демонстрации всего того, о чем я говорил здесь в статье. С его помощью вы можете:

  • Загрузить одну страницу.
  • Загрузить несколько страниц.
  • Извлечь все графические файлы с одной или нескольких страниц.
  • Извлечь все ссылки с одной или нескольких страниц.
  • Создать список всех ссылок на странице.
  • Загрузить все HTML-страницы, ссылки на которые имеются на вашей странице.
  • Скачать все страницы, URL которых присутствует в списке файла данных.

Что бы это все сделать, я создал функции:

  • Разбора HTML документа.
  • Извлечения ссылок используя функции С splitpath и makepath.
Синтаксический анализ HTML

Первая группа ключевых функций - LookForTagAndExtractValue и ExtractTagValue. Эти функции, соответственно, просматривают строку данных для на присутствие определенного тега HTML и извлекают URL из того тэга.

Первая функция, LookForTagAndExtractValue, работает, просматривая строку на предмет наличия любого тэга, определенного в таблице тэгов. Как только она находит нужный тег, она вызывает функцию ExtractTagValue, которая извлекает значение тега. Если тег или значение найдено, возвращается True, или, в противном случае, False.

Вторая функция, ExtractTagValue, просто просматривает данные, ища точно установленное ключевое слово. Как только допустимое значение найдено, возвращается указатель на него, если же значение не найдено, возвращается NULL.

Поиск URL и синтаксический анализ
Поиск

Типовой код, исследованный в разделе "Все вместе", фактически отыскивает информацию в Internet через URL. Функция выборки в NetGet, названная GetURLPage, делает больше чем приведенная выше. Она охватывает следующее:

  • Соединяется с указанным URL.
  • Производит разбор URL и извлекает имя файла.
  • Создает указанный файл.
  • Читает все данные из файла, при необходимости вызываясь нужное число раз.
  • Закрывает соединение.

Класс был написан, чтобы хранить дескриптор, возвращенный от предыдущего вызова StartInternetSession. Функция берет три параметра, которые требуют некоторого объяснения.

  • Первый параметр - URL, который нужно открыть. Можно использовать любой протокол - HTTP, FTP, Gopher. Как мы выяснили ранее, независимо от использованного протокола, открытие соединения происходит одинаково.
  • Второй параметр - корневая директория, куда вы хотите записать всю скачанную информацию. Например, если вы хотите поместить все в каталог INETDOWNLOAD, и вы скачиваете две страницы: http:/www.site.com/reference.htm и http:/www.offsite.uk/manual.htm, функция создаст три подкаталога: один названный \INETDOWNLOAD плюс два подкаталога ниже этого, названные \www.site.com и \www.offsite.uk. Причина для создания таких подкаталогов - то, что файлы с каждой отдельной страницы загружаются в соответствующую директорию, а не все вместе в директорию INETDOWNLOAD.
  • Третий параметр - указатель на буфер в памяти, который получит законченное описание выходного файла, который нужно загрузить. Не всегда очевидно, зачем это. Если вы приходите на URL ftp:/www.site.com/index.txt, то имя файла очевидно - index.txt. Но какое имя файла должно быть в случае http:/www.offsite.com/? Нет, это - не ошибка записи по буквам - не имеется никакого имени файла! В этом случае, сайт, получающий запрос, подставляет страницу "по умолчанию". Но вам нужно знать, какое имя дать файлу, что бы записать в него информацию.. Функция GetURLPage определяет, имеется ли параметры файла, в частности его имя, и если есть, то все идет стандартным образом. В противном случае будет вызвана функция GetDefaultFilespec. Эта функция генерирует название файла "по умолчанию": default.htm, default_1.htm, и так далее.
Синтаксический анализ

Как только HTML страница была загружена, она должна быть проанализирована. Это делается с помощью функции ParseURLPage. Функция включает четыре функции, подобные анализу каталога в Win32 API. Пара функций ParseOpen и ParseClose просто инициализирует и очищает структуры синтаксического анализа. ParseFirstURL и ParseNextURL написаны, чтобы использоваться в цикле - то есть Вы вызываете ParseFirstURL, чтобы отыскать первый URL в файле HTML, затем обрабатываете, и продолжаете вызывать ParseNextURL и обрабатывать файл до того момента, когда уже ничего будет обрабатывать :-).

Резюме

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


Это все на сегодня. Пока!

Алекс Jenter   jenter@rsdn.ru
Duisburg, 2002.    Публикуемые в рассылке материалы принадлежат сайту RSDN.

| Предыдущие выпуски     | Статистика рассылки