Введення у WinInet
Ще вчора Ви навіть і не думали про написання програм, що використовують інтернет протоколи, вважаючи, що це доля веб-програмістів. Але вже сьогодні перед Вами стоїть завдання прочитати/записати, передати/прийняти, отримати/послати що-небудь зі своєї програми на який-небудь інтернет-сервер. Які засоби для цього є? Скільки часу піде на їх вивчення та експерименти? Давайте розглянемо один із способів, що дозволяє вирішувати більшість подібних завдань у максимально короткі терміни.
Win32 Internet Extensions, або WinInet, є API для доступу до загальних протоколів інтернет, включаючи FTP, HTTP і Gopher. Це високорівневий API, що дозволяє, на відміну від WinSock або TCP/IP, не перейматися деталями реалізації відповідних інтернет протоколів. Усього API містить трохи менше сотні функцій на всі випадки життя, але нам для початку роботи з WinInet потрібно не більше десятка.
Необхідний мінімум
Функції WinInet API
Розберемо всі функції по порядку та розглянемо лише ті параметри, які нам будуть потрібні.
InternetOpen
Ця функція ініціалізує WinInet та повертає дескриптор, необхідний для виклику інших функцій WinInet. У разі невдачі повертається NULL. Більш детальну інформацію про помилку можна отримати, викликавши функцію GetLastError , яка повертає один із кодів, визначених у файлі wininet.h .
| lpszAgent | Задає ім'я програми, яка використовується як агент у протоколі HTTP. Сервер може визначити агента за допомогою змінної сервера HTTP_USER_AGENT. Якщо програма збирається видавати себе за MS Internet Explorer, передайте у цей параметр рядок " Mozilla/4.0 (compatible; MSIE 6.0b; Windows NT 5.0; .NET CLR 1.0.2914) " |
| dwAccessType | Визначає необхідний тип доступу (прямий або через проксі). Ми будемо використовувати значення INTERNET_OPEN_TYPE_PRECONFIG, яке встановлює тип доступу відповідно до установок у реєстрі. |
InternetConnect
Ця функція відкриває FTP, HTTP чи Gopher сесію для заданого сайту.
HttpOpenRequest
HTTP запит виконується кілька етапів: відкриття запиту, визначення HTTP заголовка, власне відправка запиту, читання і обробка даних. Ця функція, як випливає з її назви, відкриває запит HTTP.
HttpSendRequest
Надсилає запит на сервер.
InternetReadFile
InternetCloseHandle
Ця функція закриває будь-який із дескрипторів, створених попередніми функціями.
| hInternet | Дескриптор, отриманий викликом функцій InternetOpen, InternetConnect або HttpOpenRequest. |
Читаємо сторінку
Тепер ми знаємо все необхідне, щоби написати просту програму для читання HTML сторінки. Наш приклад може виглядати так:
Як бачите, все досить просто, хоча цей приклад можна зробити ще простіше. Справа в тому, що WinInet включає функцію InternetOpenUrl, яка може замінити пару HttpOpenRequest і HttpSendRequest. Але легкі шляхи не для нас, тим більше, що нас цікавить не просте читання сторінок, а повноцінне спілкування з сервером.
Що нам для цього потрібно?
Давайте з цього і почнемо.
Клас CHTTPReader
MFC містить цілий набір класів, що дозволяють працювати з WinInet, для чого потрібен ще один клас? По-перше, класи MFC - це обгортки функцій API, тому наш приклад не виглядатиме набагато простіше. Нам доведеться створювати кілька об'єктів, як і раніше, пам'ятати всі необхідні прапори і частенько заглядати вMSDN. З іншого боку, наш клас не буде універсальним, він буде працювати тільки з протоколом HTTP і мати мінімально необхідний набір функцій. Зате він буде простим і легким у використанні. По-друге, MFC - це MFC, якщо ми не хочемо використовувати MFC, то ми будемо змушені використовувати API або. написати свій клас :o)
Оголошення класу
Ось інтерфейс класу CHTTPReader:
Виділено ті функції, які ми використовуватимемо постійно. Інші можуть бути корисними, але використовувати їх не обов'язково. Нижче наведено опис методів класу CHTTPReader.
CHTTPReader
OpenInternet, OpenConnection
Автоматично викликаються під час запиту. Перша функція ініціалізує WinInet і може бути використана для вказівки імені програми. Друга відкриває сесію HTTP і дозволяє вказувати ім'я сервера.
| lpszAgent | Задає ім'я програми, яка використовується як агент у протоколі HTTP. Сервер може визначити агента за допомогою змінної сервера HTTP_USER_AGENT. |
| lpszServerName | Вказує ім'я сервера. Якщо цей параметр не заданий і ім'я сервера не в конструкторі, то як ім'я сервера використовується "localhost" . |
Надсилають запит на сервер на сервер методом "GET" або "POST".
Читає дані із сервера.
Друга версія функції читає дані у внутрішній буфер, розмір якого визначається за допомогою дзвінка GetDataSize . У разі помилки або завершення читання даних повертається NULL.
GetDataSize
Повертає розмір даних, доступних для читання.
Використовує для отримання інформації функцію HttpQueryInfo з HTTP_QUERY_CONTENT_LENGTH. Я зустрічався із ситуацією, коли ця функція повертала нуль, хоча після цього дані читалися в повному обсязіобсязі. Можна було б використовувати функцію InternetQueryDataAvailable, але з нею теж не все гаразд. Наприклад, при читанні сторінки ASP ця функція видає не розмір результуючої сторінки, а розмір самого скрипу, що, безсумнівно, є дуже цікавою інформацією, але марною для нас. В результаті, я не знаю і не можу запропонувати Вам абсолютно надійного способу отримати точну інформацію про розмір даних, що запитуються. Швидше за все, це буде працювати, але якщо Ви маєте на увазі використовувати сервери, які не можете заздалегідь протестувати, то краще не покладайтеся на ці функції.
SetDataBuffer
Встановлює розмір буфера.
| dwBufferSize | Новий розмір буфера |
CloseRequest, CloseConnection, CloseInternet
Викликаються автоматично за потреби. Визволяють відповідні ресурси.
SetDefaultHeader
Дозволяє встановлювати заголовки HTTP.
| lpszDefaultHeader | Зміст заголовка. |
Повертає код GetLastError для останнього невдалого виклику функцій WinInet.
Знову читаємо сторінку
На цей раз ми будемо використовувати клас CHTTPReader для читання тієї ж сторінки новин. Ось що з цього вийшло:
Виділені рядки - це те, що належить до запиту, інше - імітація бурхливої діяльності. Як бачите тепер все дуже просто.
Спілкування із сервером
Читання курсу валют
Давайте займемося чимось кориснішим, ніж просто читання сторінок новин. Наприклад, як це не дивно, але ми вже маємо всі засоби для читання даних про курси валют на задану дату з сервера ЦБ РФ. Наступний приклад показує цю можливість.
Фактично ми формуємо рядокзапиту, що у браузері виглядає так "http://www.cbr.ru/currency_base/D_print.asp?date_req=DD.MM.YYYY" , де замість DD, MM, YYYY потрібно підставити необхідну дату. Потім ми надсилаємо запит на сервер та парсуємо результат, виділяючи необхідну інформацію. Цей приклад чудово працює, але має один істотний недолік - він залежить від структури HTML документа, яка може будь-якої миті змінена програмістами ЦБ РФ.
Клієнт – Сервер
Тепер настав час переключити нашу увагу на розробку повноцінної клієнт-серверної програми. Те, що воно робитиме, не так важливо, важливішим є те, як воно це робитиме. Тому як приклад візьмемо простий калькулятор, точніше навіть помножувач. Ось текст ASP-скрипту нашої серверної частини програми:
Все, що нам потрібно для роботи – це виділений фрагмент, решта тексту наведена виключно для демонстрації. Можете запустити цей скрипт на виконання та переконатися, що він працює. Клацніть за наступним посиланням: calc.asp.
Тепер займемося клієнтською частиною нашої програми. Передача даних на сервер здійснюється методом "PUT" або "POST". У нас вже є функція Post, яка вміє виконувати всю необхідну роботу. Якщо ви помітили, виділений фрагмент тексту в calc.asp виглядає незвичайно для ASP-скрипту. Все правильно, наш скрипт повертає дані у форматі XML. А куди зараз без нього? :o) Наш клієнт буде отримувати результат у XML-форматі та використовувати MSXML парсер для обробки результату:
Запустіть цей приклад і переконайтесь у його працездатності. Зауважте, що всю чорну роботу з множення двох чисел виконує RSDN.завжди ласкаво просимо!
Допоміжні засоби
Для налагодження наших запитів нам, перш за все, буде потрібно інтернет-сервер. У комплект Windows 2000 входить IIS 5.0, який нам цілком підійде, хоча Ви можете використовувати будь-який інший. Багато HTML форми крім видимих полів введення містять приховані поля, які часто бувають розмазані по всьому HTML документу. Вишукування цих полів завдання не найпростіше, особливо якщо документ створений програмно і програмісту нема чого піклуватися про його читабельність. Впорається з цією проблемою нам допоможе наступний скрипт:
Для того щоб перевірити наш скрипт у дії давайте зробимо таке:
Браузер знову відобразить var.asp , але цього разу перша таблиця буде заповнена іменами полів та значеннями форми введення попередньої сторінки, тобто. Ви повинні отримати приблизно таке:
| Form Variable | Value |
| Firm | 123 |
| Urbanization | |
| Delivery Address | 123 |
| City | 123 |
| Submit | Process |
| State | 12 |
| Zip Code | 123 |
Тепер ми маємо повну картину, включаючи імена звичайних та прихованих полів та їх значення.
Де ця вулиця, де цей будинок? >8(
Скористайтеся отриманою інформацією для відповіді на це цікаве запитання.
Коментаріми відмічені місця, які нам необхідно розглянути для розуміння того, що відбувається.
Висновок
І, тим не менш, WinInet добре підходить для простих та середньої складності завдань. Якщо Вам потрібно додати до програми, наприклад, можливість online-реєстрації, то, я сподіваюся, тепер Вам знадобиться для написання найкомунікаційнішоїчастини трохи більше півгодини. Читання WWW-сторінок, як Ви могли переконатися, теж не становить жодної складності. Фактично, програмно Ви можете зробити все, що Ви можете робити у браузері, включаючи процес входу паролем. Але якщо Ви вирішите написати сам браузер. то, мабуть, для цього краще підійдуть сокети.