abclinuxu.cz AbcLinuxu.cz itbiz.cz ITBiz.cz HDmag.cz HDmag.cz abcprace.cz AbcPráce.cz
AbcLinuxu hledá autory!
Inzerujte na AbcPráce.cz od 950 Kč
Rozšířené hledání
×
    dnes 12:22 | Zajímavý článek

    Nové číslo časopisu Raspberry Pi zdarma ke čtení: Raspberry Pi Official Magazine 165 (pdf).

    Ladislav Hagara | Komentářů: 0
    dnes 10:55 | Nová verze

    Byla vydána verze 9.2 open source virtualizační platformy Proxmox VE (Proxmox Virtual Environment, Wikipedie) založené na Debianu. Přehled novinek v poznámkách k vydání a informačním videu.

    Ladislav Hagara | Komentářů: 4
    dnes 09:33 | IT novinky

    Firefox 151 podporuje Web Serial API. Pro komunikaci s různými mikrokontroléry připojenými přes USB nebo sériové porty už není nutné spouštět Chrome nebo na Chromiu postavené webové prohlížeče.

    Ladislav Hagara | Komentářů: 1
    dnes 04:44 | Nová verze

    Byla vydána nová stabilní verze 8.0 webového prohlížeče Vivaldi (Wikipedie). Postavena je na Chromiu 148. Přehled novinek i s náhledy v příspěvku na blogu.

    Ladislav Hagara | Komentářů: 0
    včera 21:33 | Bezpečnostní upozornění

    Ve FreeBSD byla nalezena a opravena zranitelnost FatGid aneb CVE-2026-45250. Jedná se o lokální eskalaci práv. Neprivilegovaný uživatel se může stát rootem.

    Ladislav Hagara | Komentářů: 0
    včera 14:33 | IT novinky

    Společnost Flipper Devices oznámila Flipper One. Zcela nový Flipper postavený od nuly. Jedná se o open-source linuxovou platformu založenou na čipu Rockchip RK3576. Hledají se dobrovolníci pro pomoc s dokončením vývoje (ovladače, testování, tvorba modulů).

    Ladislav Hagara | Komentářů: 2
    včera 14:00 | Nová verze

    Vývojáři Wine oznámili vydání verze 2.0 knihovny vkd3d pro překlad volání Direct3D na Vulkan. Přehled novinek na GitLabu.

    Ladislav Hagara | Komentářů: 0
    včera 11:33 | Nová verze

    Společnost Red Hat oznámila vydání Red Hat Enterprise Linuxu (RHEL) 10.2 a 9.8. Vedle nových vlastností a oprav chyb přináší také aktualizaci ovladačů a předběžné ukázky budoucích technologií. Vypíchnout lze CLI AI asistenta goose. Podrobnosti v poznámkách k vydání (10.2 a 9.8).

    Ladislav Hagara | Komentářů: 0
    včera 05:11 | Nová verze

    Organizace Apache Software Foundation (ASF) vydala verzi 30 integrovaného vývojového prostředí a vývojové platformy napsané v Javě NetBeans (Wikipedie). Přehled novinek na GitHubu. Instalovat lze také ze Snapcraftu a Flathubu.

    Ladislav Hagara | Komentářů: 0
    včera 05:00 | Nová verze

    Byla vydána nová verze 7.0 svobodného open source redakčního systému WordPress. Kódové jméno Armstrong bylo vybráno na počest amerického jazzového trumpetisty a zpěváka Louise Armstronga (What A Wonderful World).

    Ladislav Hagara | Komentářů: 0
    Které desktopové prostředí na Linuxu používáte?
     (13%)
     (8%)
     (2%)
     (14%)
     (31%)
     (4%)
     (6%)
     (3%)
     (16%)
     (26%)
    Celkem 1679 hlasů
     Komentářů: 30, poslední 3.4. 20:20
    Rozcestník

    Konzolové programy v Qt 4 – 2 (práce s HTTP a FTP)

    1. 9. 2009 | David Watzke | Programování | 4381×

    V dnešním díle se budu věnovat modulu QtNetwork, konkrétně si ukážeme nějaké základy práce s protokoly HTTP a FTP.

    Obsah

    Úvod do síťování v Qt

    link

    Práci s protokoly HTTP a FTP implementují třídy QHttpQFtp, které jsou v Qt dostupné už mnoho let. Ve verzi 4.4 se objevila třída QNetworkAccessManager, která poskytuje jednodušší, ale přesto mocnější API a vývojáři doporučují její použití v nových programech.

    Síťování je asynchronní a využívá technologie signálů a slotů. Pošlete požadavek, vytvoří se objekt s odpovědí a tento objekt potom vyšle signál, když je požadavek vyřízený nebo když dojde k chybě.

    Při vytváření projektů pracujících s modulem QtNetwork v Qt Creatoru si nezapomeňte modul vyžádat. Pokud projekt vytváříte ručně, tak si do .pro souboru přidejte řádek QT += network.

    HTTP hlavičky

    link

    Ukážeme si, jak poslat HTTP požadavek GET a vypsat získané hlavičky. Program funguje takto:

    $ ./httphead http://www.abclinuxu.cz/
    Expires: Fri, 22 Dec 2000 05:00:00 GMT
    Set-Cookie: JSESSIONID=5117noj9m1ik;Path=/
    Content-Type: text/html; charset=utf-8
    Last-Modified: Thu, 27 Aug 2009 13:38:35 GMT
    Cache-Control: no-cache, must-revalidate
    Pragma: no-cache
    Content-Encoding: gzip
    Server: Jetty(6.1.11)

    http.h: API.

    #ifndef HTTP_H
    #define HTTP_H
    
    #include <QObject>
    #include <QNetworkReply>
    #include <QTextStream>
    
    class QNetworkAccessManager;
    
    class HTTP : public QObject
    {
    	Q_OBJECT
    public:
    	HTTP();
    	int run();
    
    private:
    	QNetworkAccessManager *manager;
    	// objekt pro zápis na std. výstup
    	QTextStream cout;
    
    private slots:
    	void gotReply(QNetworkReply* reply);
    	void gotError(QNetworkReply::NetworkError);
    };
    
    #endif // HTTP_H
    

    http.cpp

    #include "http.h"
    
    /*
    #include <QCoreApplication>
    #include <QNetworkAccessManager>
    #include <QNetworkRequest>
    #include <QStringList>
    */
    
    // includne celý modul QtNetwork, který s sebou vtáhne QtCore
    #include <QtNetwork>
    // tohle potřebujeme pro stdout
    #include <cstdio>
    
    HTTP::HTTP() : cout(stdout, QIODevice::WriteOnly)
    {
    	manager = new QNetworkAccessManager(this);
    
    	// spojíme signál značící vyřízení požadavku se slotem,
    	// který zpracuje odpověď
    	connect(manager, SIGNAL(finished(QNetworkReply*)),
    		this, SLOT(gotReply(QNetworkReply*)));
    }
    
    int HTTP::run()
    {
    	// zkontrolujeme počet argumentů, případně vypíšeme nápovědu
    	QStringList args = qApp->arguments();
    	if(args.size() != 2)
    	{
    		cout << "usage: " << args.at(0) << " [http url]\n";
    		cout.flush();
    		// odsud nelze ukončit program běžným způsobem,
    		// vysvětlení najdete u souboru main.cpp
    		return 1;
    	}
    
    	QString url = args.at(1);
    	// pošleme HTTP požadavek HEAD na dané URL, uložíme si ukazatel na odpověď
    	QNetworkReply* reply = manager->head(QNetworkRequest(QUrl(url)));
    	// spojíme odpověď se slotem, který zpracuje případnou chybu
    	connect(reply, SIGNAL(error(QNetworkReply::NetworkError)),
    		this, SLOT(gotError(QNetworkReply::NetworkError)));
    
    	return 0;
    }
    
    // vypíše všechny hlavičky a ukončí program
    void HTTP::gotReply(QNetworkReply* reply)
    {
    	foreach(QByteArray header, reply->rawHeaderList())
    	{
    		QByteArray value = reply->rawHeader(header);
    		cout << header << ": " << value << "\n";
    	}
    	cout.flush();
    	qApp->exit(0);
    }
    
    // vypíše chybu a ukončí program
    void HTTP::gotError(QNetworkReply::NetworkError e)
    {
    	switch(e)
    	{
    	case QNetworkReply::NoError:
    		break;
    	case QNetworkReply::ConnectionRefusedError:
    		cout << tr("connection refused") << "\n";
    		break;
    	case QNetworkReply::RemoteHostClosedError:
    		cout << tr("the remote server closed the connection") << "\n";
    		break;
    	case QNetworkReply::HostNotFoundError:
    		cout << tr("host not found") << "\n";
    		break;
    	case QNetworkReply::TimeoutError:
    		cout << tr("connection timed out") << "\n";
    		break;)
    	case QNetworkReply::ProtocolUnknownError:
    		cout << tr("unknown protocol (did you forget http:// ?)") << "\n";
    		break;
    	default:
    		cout << tr("an error occured") << "\n";
    		break;
    	}
    	cout.flush();
    	qApp->exit(2);
    }
    

    main.cpp: V metodě run() nelze ukončit program klasickým způsobem, protože ještě neběží smyčka událostí. Jelikož zde program ukončit potřebujeme (pokud uživatel nezadá argument – URL), tak jsem zvolil jedno z mnoha řešení, jak to obejít.

    #include <QCoreApplication>
    
    #include "http.h"
    
    int main(int argc, char *argv[])
    {
    	QCoreApplication a(argc, argv);
    
    	HTTP main;
    	if(main.run() != 0)
    		return 1;
    
    	return a.exec();
    }
    

    Zdrojáky si můžete stáhnout v archívu httphead.tar.bz2.

    Stahování souborů

    link

    Jelikož má QNetworkAccessManager takové pěkné rozhraní pro stahování souborů, rozhodl jsem se předvést zde metodu get() právě pro stahování z FTP.

    Výstup programu vypadá následovně:

    $ ./ftpget ftp://gentoo.mirror.web4u.cz/releases/amd64/autobuilds/20090716/install-amd64-minimal-20090716.iso
    downloaded 121188352 bytes (out of 121188352), which is 100%
    download finished, file saved as install-amd64-minimal-20090716.iso
    
    $ ./ftpget http://gentoo.mirror.web4u.cz/snapshots/portage-20090818.tar.bz2
    downloaded 36430733 bytes (out of 36430733), which is 100%
    download finished, file saved as portage-20090818.tar.bz2

    ftpget.h: API.

    #ifndef FTPGET_H
    #define FTPGET_H
    
    #include <QObject>
    #include <QTextStream>
    #include <QNetworkReply>
    
    class QFile;
    class QNetworkAccessManager;
    
    class FtpGet : public QObject
    {
    	Q_OBJECT
    public:
    	FtpGet();
    	int run();
    
    private:
    	QFile* file;
    	QString fileName;
    	QNetworkAccessManager* manager;
    	QNetworkReply* reply;
    	QTextStream cout;
    
    private slots:
    	void downloadFinished(QNetworkReply*);
    	void showProgress(qint64, qint64);
    	void writeData();
    	void handleError(QNetworkReply::NetworkError);
    };
    
    #endif // FTPGET_H
    

    ftpget.cpp:

    #include "ftpget.h"
    
    #include <QtNetwork>
    
    FtpGet::FtpGet() : cout(stdout, QIODevice::WriteOnly)
    {
    	manager = new QNetworkAccessManager(this);
    
    	connect(manager, SIGNAL(finished(QNetworkReply*)),
    		this, SLOT(downloadFinished(QNetworkReply*)));
    }
    
    int FtpGet::run()
    {
    	// zkontrolujeme počet argumentů, případně vypíšeme nápovědu
    	QStringList args = qApp->arguments();
    	if(args.size() != 2)
    	{
    		cout << "usage: " << args.at(0) << " [ftp://file]\n";
    		cout.flush();
    		return 1;
    	}
    
    	QUrl url(args.at(1));
    
    	// získáme z URL název souboru
    	fileName = url.path().split('/').last();
    	if(fileName.isEmpty())
    		fileName = QString("file_from_%1").arg(url.host());
    
    	// otevřeme soubor pro zápis
    	file = new QFile(fileName);
    	if(!file->open(QIODevice::WriteOnly))
    	{
    		cout << "could not open the file (" << fileName << ")\n";
    		cout.flush();
    		return 1;
    	}
    
    	// začneme stahovat
    	reply = manager->get(QNetworkRequest(url));
    
    	// propojíme signály s funkcemi pro zápis, výpis průběhu a zpracování chyb
    	connect(reply, SIGNAL(downloadProgress(qint64,qint64)),
    		this, SLOT(showProgress(qint64,qint64)));
    	connect(reply, SIGNAL(error(QNetworkReply::NetworkError)),
    		this, SLOT(handleError(QNetworkReply::NetworkError)));
    	connect(reply, SIGNAL(readyRead()), this, SLOT(writeData()));
    
    	return 0;
    }
    
    // zapíše průběžně stažená data
    void FtpGet::writeData()
    {
    	file->write(reply->readAll());
    }
    
    // zavře soubor, informuje o dokončení stahování a ukončí program
    void FtpGet::downloadFinished(QNetworkReply* reply)
    {
    	Q_UNUSED( reply )
    
    	if(file && file->isOpen())
    		file->close();
    	cout << QString("\ndownload finished, file saved as %1\n").arg(fileName);
    	cout.flush();
    	qApp->quit();
    }
    
    // vypíše průběh stahování
    void FtpGet::showProgress(qint64 dl, qint64 all)
    {
    	// procenta
    	int perc = 0;
    
    	// spočítá kolik procent je staženo (pokud to lze)
    	if(dl > 0 && all > 0)
    		perc = dl / (all / 100);
    
    	// pomocný řetězec s celkovou velikostí
    	QString sizestr = (all == -1) ? "[unknown total size]" : QString::number(all);
    
    	// pomocný řetězec s procenty
    	QString percstr = "";
    	if (perc != 0)
    		percstr = QString(", which is %1%").arg(perc);
    
    	// vypíše info o průběhu stahování
    	cout << QString("\rdownloaded %1 bytes (out of %2)").arg(dl).arg(sizestr) << percstr << "\t\t";
    }
    
    // zpracuje chybu (v tomto případě jen vypíše chybový kód, viz první program pro úplné řešení)
    void FtpGet::handleError(QNetworkReply::NetworkError e)
    {
    	cout << "\nan error ocurred (code #" << e << "), see http://qt.nokia.com/doc/qnetworkreply.html#NetworkError-enum\n";
    	qApp->exit(2);
    }
    

    main.cpp:

    #include <QCoreApplication>
    
    #include "ftpget.h"
    
    int main(int argc, char *argv[])
    {
    	QCoreApplication a(argc, argv);
    
    	FtpGet main;
    	if(main.run() != 0)
    		return 1;
    
    	return a.exec();
    }
    

    Zdrojáky si můžete stáhnout v archívu ftpget.tar.bz2.

           

    Hodnocení: 100 %

            špatnédobré        

    Nástroje: Tisk bez diskuse

    Tiskni Sdílej: Linkuj Jaggni to Vybrali.sme.sk Google Del.icio.us Facebook

    Komentáře

    Vložit další komentář

    1.9.2009 00:25 sharpiq
    Rozbalit Rozbalit vše Re: Konzolové programy v Qt 4 – 2 (práce s HTTP a FTP)

    Zdravim,

    mozno mi niekto bude vediet poradit - ked som posledne robil s metodami ktore pracuju s HTTP/HTTPS napriek tomu ze Qt network je deklarovane ako asynchronne na Windows strojoch to sposobovalo "zamrznutie" UI aplikacie pri poziadavkach na server. Ked som to prehnal cez gdb tak Qt vytvoralo cca 5-6 threadov na kazde volanie. Nevie niekto cim to moze byt sposobovane? Vyskytovalo sa to len na Windows, Qt bolo verzie 4.2.2.

    David Watzke avatar 1.9.2009 00:44 David Watzke | skóre: 74 | blog: Blog... | Praha
    Rozbalit Rozbalit vše Re: Konzolové programy v Qt 4 – 2 (práce s HTTP a FTP)

    Zkus aktuální verzi Qt (dnes 4.5.2) a případně nahlaš chybu vývojářům (viz web qt.nokia.com). Půjde o windows-specific bug.

    Pokud to zatím potřebuješ obejít, tak síťování dělej v odděleném vlákně QThread.

    “Being honest may not get you a lot of friends but it’ll always get you the right ones” ―John Lennon
    1.9.2009 10:40 Ladicek | skóre: 28 | blog: variace | Havlíčkův brod
    Rozbalit Rozbalit vše Re: Konzolové programy v Qt 4 – 2 (práce s HTTP a FTP)
    Má nějaký smysl, že signál finished spojuješ se slotem gotReply/downloadFinished už v konstruktoru, zatímco všechny ostatní až v metodě run (a to dokonce teprve poté, co spustíš samotné stahování)? Intuitivně bych to všechno dělal na jednom místě (asi v run před zahájením stahování)…
    Ještě na tom nejsem tak špatně, abych četl Viewegha.
    David Watzke avatar 1.9.2009 11:17 David Watzke | skóre: 74 | blog: Blog... | Praha
    Rozbalit Rozbalit vše Re: Konzolové programy v Qt 4 – 2 (práce s HTTP a FTP)
    Jo, má to smysl. V konstruktoru dělám spojení s tím managerem, zatímco v tý metodě spojuju sloty se signály socketu - a ten socket získám teprve po spuštění metody (head) manageru, takže to jinak ani nejde.
    “Being honest may not get you a lot of friends but it’ll always get you the right ones” ―John Lennon
    1.9.2009 11:50 Ladicek | skóre: 28 | blog: variace | Havlíčkův brod
    Rozbalit Rozbalit vše Re: Konzolové programy v Qt 4 – 2 (práce s HTTP a FTP)
    Ha, toho jsem si nevšiml, jak jsem to tak rychle prolítnul. Díky.
    Ještě na tom nejsem tak špatně, abych četl Viewegha.
    1.9.2009 10:54 Jirka
    Rozbalit Rozbalit vše void QTcpServer::incomingConnection ( int socketDescriptor )

    Jak korektne implementovat void QTcpServer::incomingConnection ( int socketDescriptor ) pro potomka tridy QTcpServer? Prijde mi, ze to neni mozne. Ta metoda je virtualni, aby mohla byt prepsana. Ale jeji implementace v QTcpServer vyuziva privatni funkce, takze kdyz ji chce nekdo implementovat znovu, nemuze podle me zajistit stejnou funkcnost.

    David Watzke avatar 1.9.2009 11:18 David Watzke | skóre: 74 | blog: Blog... | Praha
    Rozbalit Rozbalit vše Re: void QTcpServer::incomingConnection ( int socketDescriptor )
    Pokud chceš stejnou funkčnost, tak ji prostě nech jak je. Nemusíš ji reimplementovat za každou cenu. Pokud chceš aby dělala to, co dělá + něco navíc, tak si vytvoř vlastní a volej v ní
    QTcpServer::incomingConnection(socketDescriptor);
    “Being honest may not get you a lot of friends but it’ll always get you the right ones” ―John Lennon
    29.6.2023 09:55 Adilkhatri
    Rozbalit Rozbalit vše Re: Konzolové programy v Qt 4 – 2 (práce s HTTP a FTP)
    A to a great degree brilliant blog passage. We are really grateful for your blog passage. fight, law usage You will find an extensive measure of techniques in the wake of heading off to your post. I was absolutely examining for. An obligation of appreciation is all together for such post and please keep it up. Mind blowing work. 먹튀검증

    Založit nové vláknoNahoru

    ISSN 1214-1267   www.czech-server.cz
    © 1999-2015 Nitemedia s. r. o. Všechna práva vyhrazena.