KnigaRead.com/
KnigaRead.com » Компьютеры и Интернет » Программирование » Жасмин Бланшет - QT 4: программирование GUI на С++

Жасмин Бланшет - QT 4: программирование GUI на С++

На нашем сайте KnigaRead.com Вы можете абсолютно бесплатно читать книгу онлайн Жасмин Бланшет, "QT 4: программирование GUI на С++" бесплатно, без регистрации.
Перейти на страницу:

get(file_N_1)

emit listInfo(file_N_2)

get(file_N_2)

emit done()

Если файл фактически оказывается каталогом, он добавляется в список pendingDirs и, когда завершается скачивание последнего файла, полученного текущей командой list(), выдается новая команда cd(), за которой следует новая команда list() для следующего каталога, ожидающего обработки, и весь процесс повторяется для нового каталога. Скачиваются новые файлы, и в список pendingDirs добавляются новые каталоги до тех пор, пока не будут скачаны все файлы из всех каталогов и список pendingDirs в результате не станет пустым.

Если возникнет сетевая ошибка при загрузке пятого файла, скажем, из двадцати файлов в каталоге, остальные файлы не будут скачаны. Если бы мы захотели скачать как можно больше файлов, то один из способов заключается в выполнении по одной операции GET и ожидании сигнала done(bool) перед выполнением новой операции GET. В функции listInfo() мы бы просто добавили имя файла в конец списка QStringList вместо немедленного вызова get(), а в слоте done(bool) мы бы вызывали функцию get() для следующего загружаемого файла из списка QStringList. Последовательность команд выглядела бы так:

connectToHost(host, port)

login()

cd(directory_1)

list()

cd(directory_N)

list()

emit listInfo(file_1_1)

emit listInfo(file_1_2)

emit listInfo(file_N_1)

emit listInfo(file_N_2)

emit done()

get(file_1_1)

emit done()

get(file_1_2)

emit done()

get(file_N_1)

emit done()

get(file_N_2)

emit done()

Еще одно решение могло бы заключаться в применении одного объекта QFtp для каждого файла. Это позволило бы нам скачивать файлы из сети параллельно, используя отдельные FTP—соединения.

01 int main(int argc, char *argv[])

02 {

03 QCoreApplication app(argc, argv);

04 QStringList args = app.arguments();

05 if (args.count() != 2) {

06 cerr << "Usage: spider url" << endl << "Example:" << endl

07 << " spider ftp://ftp.trolltech.com/freebies/leafnode" << endl;

08 return 1;

09 }

10 Spider spider;

11 if (!spider.getDirectory(QUrl(args[1])))

12 return 1;

13 QObject::connect(&spider, SIGNAL(done()), &app, SLOT(quit()));

14 return app.exec();

15 }

Функция main() завершает программу. Если пользователь не задает адрес URL в командной строке, мы выдаем сообщение об ошибке и завершаем программу.

В обоих примерах применения протокола FTP данные, полученные функцией get(), записывались в объект QFile. Это не обязательно должно быть так. Если бы мы захотели хранить данные в памяти, мы могли бы использовать QBuffer — подкласс QIODevice, являющийся оболочкой массива QByteArray. Например:

QBuffer *buffer= new QBuffer;

buffer->open(QIODevice::WriteOnly);

ftp.get(urlInfo.name(), buffer);

Мы могли бы также не задавать в функции get() аргумент с устройством ввода—вывода или передать нулевой указатель. Класс QFtp тогда генерирует сигнал readyRead() при поступлении каждой новой порции данных и данные могут считываться при помощи функции read() или readAll().

Написание НТТР—клиента

Класс QHttp реализует клиентскую часть протокола HTTP в Qt. Он содержит различные функции для выполнения самых распространенных операций протокола HTTP, включая get() и post(), и обеспечивает средство выполнения произвольных запросов HTTP. Если вы прочитали предыдущий раздел о классе QFtp, вы обнаружите, что существует много общего у классов QFtp и QHttp.

Класс QHttp работает асинхронно. Когда мы вызываем такие функции, как get() или post(), управление сразу же возвращается к нам, а пересылка данных осуществляется после передачи управления обратно в цикл обработки событий Qt. Это обеспечивает работоспособность интерфейса пользователя во время обработки запросов HTTP.

Мы рассмотрим пример консольного приложения с именем httpget, демонстрирующего способ загрузки файла с использованием протокола HTTP. Мы не приводим здесь заголовочный файл, поскольку данный пример очень напоминает пример ftpget, который мы использовали в предыдущем разделе.

01 HttpGet::HttpGet(QObject *parent)

02 : QObject(parent)

03 {

04 …

05 connect(&http, SIGNAL(done(bool)), this, SLOT(httpDone(bool)));

06 }

В конструкторе мы подсоединяем сигнал done(bool) объекта QHttp к закрытому слоту httpDone(bool).

01 bool HttpGet::getFile(const QUrl &url)

02 {

03 if (!url.isValid()) {

04 сегг << "Error: Invalid URL" << endl;

05 return false;

06 }

07 if (url.scheme() != "http") {

08 cerr << "Error: URL must start with 'http:'" << endl;

09 return false;

10 }

11 if (url.path().isEmpty()) {

12 cerr << "Error: URL has no path" << endl;

13 return false;

14 }

15 QString localFileName = QFileInfo(url.path()).fileName();

16 if (localFileName.isEmpty())

17 localFileName = "httpget.out";

18 file.setFileName(localFileName);

19 if (!file.open(QIODevice::WriteOnly)) {

20 cerr << "Error: Cannot open "

21 << qPrintable(file.fileName()) << " for writing: "

22 << qPrintable(file.errorString()) << endl;

23 return false;

24 }

25 http.setHost(url.host(), url.port(80));

26 http.get(url.path(), &file);

27 http.close();

28 return true;

29 }

Функция getFile() проверяет ошибочные ситуации так же, как рассмотренная ранее функция FtpGet::getFile(), и использует тот же подход при задании имени локального файла. При загрузке файлов с веб-сайта не требуется входить в систему, поэтому мы просто указываем хост и порт (используя стандартный для HTTP порт 80, если его нет в URL) и скачиваем данные в файл, заданный вторым аргументом функции QHttp::get().

Запросы HTTP ставятся в очередь и обрабатываются асинхронно в цикле обработки событий Qt. На завершение выполнения запросов указывает сигнал done(bool) объекта QHttp, который мы подсоединили к слоту httpDone(bool) в конструкторе.

01 void HttpGet::httpDone(bool еггог)

02 {

03 if (еггог) {

04 сегг << "Еггог: " << qPrintable(http.errorString()) << endl;

05 } else {

06 сегг << "File downloaded as " << qPrintable(file.fileName()) << endl;

07 }

08 file.close();

09 emit done();

10 }

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

Функция main() очень похожа на такую же функцию в примере ftpget:

01 int main(int argc, char *argv[])

02 {

03 QCoreApplication app(argc, argv);

04 QStringList args = app.arguments();

05 if (args.count() != 2) {

06 cerr << "Usage: httpget url" << endl << "Example:" << endl

07 << " httpget http://doc.trolltech.com/qq/index.html" << endl;

08 return 1;

09 }

10 HttpGet getter;

11 if (!getter.getFile(QUrl(args[1])))

12 return 1;

13 QObject::connect(&getter, SIGNAL(done()), &app, SLOT(quit()));

14 return app.exec();

15 }

Класс QHttp содержит много операций, включая setHost(), get(), post() и head(). Если для входа на сайт необходимо выполнить аутентификацию пользователя, setUser() может использоваться для установки имени пользователя и пароля. QHttp может использовать сокет, указанный программистом, а не свой собственный внутренний QTcpSocket. Это делает возможным применение безопасного сокета QtSslSocket (который предоставляется компонентом Qt Solution компании «Trolltech») для работы с HTTP через SSL.

Мы можем применять функцию post() для пересылки пар «имя = значение» в сценарий CGI:

http.setHost("www.example.com");

http.post("/cgi/somescript.py", "x=200&y=320", &file);

Мы можем передавать данные в виде 8-битовой строки либо передавать открытое устройство QIODevice, например QFile. Для обеспечения большего контроля мы можем использовать функцию request(), которая принимает произвольные заголовок и данные HTTP. Например:

QHttpRequestHeader header("POST", "/search.html");

header.setValue("Host", "www.trolltech.com");

Перейти на страницу:
Прокомментировать
Подтвердите что вы не робот:*