Устройство приложения ConsoleFtp
Для приложения ConsoleFtp мы использовали операторы потокового ввода/вывода << и >>, а также функции new и free. Поэтому нам понадобилось включить файлы iostream.h и stdlib.h:
#include <iostream.h>
#include <stdlib.h>
Наряду со стандартными функциями библиотеки языка Си, наше приложение будет пользоваться классами WinInet, входящими в библиотеку MFC. Поэтому мы включили в исходный текст приложения файлы afx.h и afxinet.h:
#include <afx.h>
#include <afxinet.h>
Определяя главную функцию приложения, мы указали для нее параметры argc и argv. Они позволяют получить параметры, указанные при запуске приложения в командной строке:
int main(int argc, char* argv[])
{
}
¨ Напомним, что через argc передается количество параметров указанных приложению, а через argv - список указателей на эти параметры
Пользователь должен указать нашему приложению всего один параметр, содержащий URL адрес сервера FTP. Если приложение запущено без параметра или указано большее количество параметров, то мы отображаем на экране информацию о формате вызова приложения:
if (argc != 2)
{
cout << "Programm format: ConsoleFtp <URL>" << endl;
cout << " <URL> - URL address of FTP" << endl << endl;
return -1;
}
Параметр, указанный при вызове приложения, записываем в текстовую строку sUrlAdress. Если параметр задан правильно он должен содержать URL адрес сервера FTP:
CString sUrlAdress;
sUrlAdress = argv[1];
Отображаем адрес сервера FTP на экране, чтобы быть уверенным в том что он задан правильно:
cout << "URL address: " << sUrlAdress << endl << endl;
Далее мы объявляем временные переменные, которые будут использоваться при разборе адреса URL. Целью такого разбора будет выделение из адреса URL имени сервера FTP:
// Имя сервера
CString sServer;
// Имя объекта на который указывает адрес URL
CString sObject;
// Номер порта
INTERNET_PORT nPort;
// Тип сервиса или тип протокола
DWORD dwServiceType;
Сам разбор адреса URL, записанного в строке sUrlAdress, выполняется с помощью функции AfxParseURL. Заметим, что это пожалуй единственная функция библиотеки MFC, относящаяся к WinInet, которая не требует предварительно создать сеанс связи - объект класса CInternetSession.
Исходный адрес URL передается функции AfxParseURL через параметр sUrlAdress, а результат записывается в переменные dwServiceType, sServer, sObject, nPort. Нас будут интересовать только две переменные dwServiceType и sServer. В переменную dwServiceType функция AfxParseURL записывает тип сервиса, указанный в адресе sUrlAdress, а в строку sServer - имя сервера:
if (!AfxParseURL(sUrlAdress, dwServiceType, sServer,
sObject, nPort))
{
cout << "AfxParseURL Error" << endl;
return -1;
}
if(dwServiceType != AFX_INET_SERVICE_FTP)
{
cout << "URL Address not FTP server" << endl;
return -1;
}
Если вы указали неправильный адрес URL или тип сервиса, не соответствующий серверу FTP, то на экран выводится предупреждающее сообщение и работа приложения завершается. Если адрес сервера указан верно, приложение создает сеанс связи с Internet. Для этого мы объявляем указатель на объект класса CInternetSession, а затем создаем сам объект, используя функцию new:
// Указатель на объект класса CInternetSession
CInternetSession* m_InternetSession = NULL;
// Инициализируем сеанс работы с WinInet - создаем объект
// класса CInternetSession catch
m_InternetSession = new CInternetSession("Connecter");
Конструктор класса CInternetSession имеет много параметров, но мы все их используем по умолчанию, кроме первого параметра, через который мы задаем имя сеанса - Connecter. Если вы опустите и этот параметр конструктора, то в качестве имени сеанса будет взято имя приложения.
¨ В случае консольного приложения попытка определить его имя по умолчанию приводит к ошибке, которую вы сможете заметить, если запустите приложение в режиме отладки
Теперь можно попытаться соединиться с сервером FTP. Для этого следует вызвать метод GetFtpConnection класса CInternetSession только что созданного объекта m_InternetSession. В случае ошибки этот метод может вызвать исключение CInternetException. Поэтому вызов метода GetFtpConnection мы помещаем в блок try и определяем для него соответствующий блок catch, обрабатывающий исключение CInternetException:
// Исключения, вызванные в этом блоке try обрабатываются
// следующим блоком catch
try
{
// . . .
}
catch (CInternetException* pEx)
{
// . . .
}
Обработчик исключения CInternetException вызывает метод GetErrorMessage для полученного исключения. Он записывает во временный буфер szErr причину вызова исключения. Если текстовое описание исключения доступно, метод GetErrorMessage возвращает ненулевое значение. В этом случае мы отображаем полученный текст на экране:
// Обрабатываем исключение CInternetException
TCHAR szErr[1024]; // временный буфер для сообщения
// Выводим сообщение об ошибке
if (pEx->GetErrorMessage(szErr, 1024))
cout << "Error: " << szErr << endl << endl;
Затем завершаем обработку исключения, вызывая для него метод Delete. Он удаляет объект, представляющий исключение, из оперативной памяти:
// Удаляем исключение
pEx->Delete();
Вернемся к блоку try. В нем приложение исполняет свою главную задачу - пытается установить соединение с сервером FTP. Адрес сервера FTP передается методу GetFtpConnection класса CInternetSession. Если соединение с сервером будет установлено, то этот метод вернет указатель на объект класса CFtpConnection и мы запишем его во временную переменную m_FtpConnection:
// Определяем указатель на объект класса CFtpConnection
CFtpConnection* m_FtpConnection = NULL;
// Пытаемся соединиться с сервером sServer
m_FtpConnection =
m_InternetSession -> GetFtpConnection( sServer );
Если попытка соединиться с сервером окажется неудачной, то метод GetFtpConnection вызовет исключение CInternetException и оно будет обработано соответствующим блоком catch.
В случае успешного соединения с сервером FTP, приложение отображает на экране соответствующее сообщение:
// Выводим сообщение об успешном соединении
cout << "Connect to FTP server established" << endl;
Больше приложение ConsoleFtp ничего не делает с сервером, поэтому закрываем соединение с сервером и удаляем соответствующий объект m_FtpConnection из памяти (этот объект создается методом GetFtpConnection):
// Закрываем соединение с сервером FTP
m_FtpConnection -> Close();
// Удаляем объект m_FtpConnection
delete( m_FtpConnection );
Перед окончанием работы приложения, завершаем сеанс связи, вызывая метод Close класса CInternetSession, а затем удаляем соответствующий объект из памяти, вызывая оператор delete:
// Завершаем сеанс связи
m_InternetSession -> Close();
// Удаляем объект m_InternetSession
delete(m_InternetSession);
Конечно, приложение ConsoleFtp демонстрирует только самые основные принципы использования классов WinInet. В следующем разделе мы приведем еще одно приложение для работы с серверами FTP. Приложение FtpView значительно сложнее чем ConsoleFtp. Оно позволяет пользователю просматривать структуру каталогов сервера FTP и названия записанных в них файлов. Несколько позже мы модифицируем приложение FtpView так, чтобы его можно было использовать для загрузки файлов и будем вносить в него небольшие изменения для демонстрации различных приемов работы с серверами FTP.