<a target="_blank" href="http://bbs.qter.org/forum.php?mod=viewthread&tid=577">樓主</a>
發表于 2013-8-28 17:21:28 | 檢視:
637| 回複: 8
http
版權聲明
該文章原創于作者yafeilinux,轉載請注明出處!
導語
http(hypertext transfer protocol,超文本傳輸協定)是一個用戶端和伺服器端請求和應答的标準。在qt的網絡子產品中提供了網絡通路接口來實作http程式設計。網絡通路接口是執行一般的網絡操作的類的集合,該接口在特定的操作和使用的協定(例如,通過http進行擷取和發送資料)上提供了一個抽象層,隻為外部暴露出了類、函數和信号。
上一節中我們已經提到過了,現在qt中使用qnetworkaccessmanager類和qnetworkreply類來進行http的程式設計。網絡請求由qnetworkrequest類來表示,它也作為與請求有關的資訊(例如,任何頭資訊和使用加密)的容器。在建立請求對象時指定的url決定了請求使用的協定,目前支援http、ftp和本地檔案urls的上傳和下載下傳。qnetworkaccessmanager類用來協調網絡操作,每當一個請求建立後,該類用來排程它,并發射信号來報告進度。該類還協調cookies的使用,身份驗證請求,及其代理的使用等。對于網絡請求的應答使用qnetworkreply類表示,它會在請求被完成排程時由qnetworkaccessmanager來建立。qnetworkreply提供的信号可以用來單獨的監視每一個應答。
下面我們先講解一個簡單下載下傳網頁的例子,然後将其擴充為可以下載下傳任何檔案。
環境:windows xp + qt 4.8.5+qt creator 2.8.0
目錄
一、簡單的網頁浏覽功能
二、實作下載下傳檔案功能
正文
1.建立qt gui應用,項目名稱為http,基類使用預設的qmainwindow即可,類名為mainwindow。
2.完成後打開http.pro檔案,然後添加下面一行代碼來使用網絡子產品:
qt += network
然後儲存該檔案。
3.下面打開mainwindow.ui檔案進入設計模式,向界面上添加一個text browser部件。效果如下圖所示。
4.打開mainwindow.h檔案,先包含頭檔案:#include <qtnetwork>
然後添加一個private私有對象定義:qnetworkaccessmanager
*manager;
最後添加一個私有槽聲明:
private slots:
void replyfinished(qnetworkreply *);
5.下面到mainwindow.cpp檔案中,先在構造函數中添加如下代碼:
manager = new qnetworkaccessmanager(this);
connect(manager, signal(finished(qnetworkreply*)),
this,slot(replyfinished(qnetworkreply*)));
manager->get(qnetworkrequest(qurl("http://www.qter.org")));
這裡先建立了一個qnetworkaccessmanager類的執行個體,它用來發送網絡請求和接收應答。然後關聯了管理器的finished()信号和我們自定義的槽,每當網絡應答結束時都會發射這個信号。最後使用了get()函數來發送一個網絡請求,網絡請求使用qnetworkrequest類表示,get()函數傳回一個qnetworkreply對象。除了get()函數,管理器還提供了發送http
post請求的post()函數。
6.下面添加槽的定義:
void mainwindow::replyfinished(qnetworkreply *reply)
{
qtextcodec *codec = qtextcodec::codecforname("utf8");
qstring all = codec->tounicode(reply->readall());
ui->textbrowser->settext(all);
reply->deletelater();
}
因為qnetworkreply繼承自qiodevice類,是以可以操作一般的i/o裝置一樣來操作該類。這裡使用了readall()函數來讀取所有的應答資料,為了正常顯示中文,使用了qtextcodec類來轉換編碼。在完成資料的讀取後,需要使用deletelater()來删除replay對象。
7.因為這裡使用了qtextcodec類,是以還需要在mainwindow.cpp檔案中包含頭檔案
#include <qtextcodec>
下面運作程式,效果如下圖所示。
這裡再将整個過程簡答叙述一遍:上面實作了最簡單的應用http協定下載下傳網頁的功能。qnetworkaccessmanager類用于發送網絡請求和接受回複,具體來說,它是用qnetworkrequest 類來管理請求,qnetworkreply類進行接收回複,并對資料進行處理。
在上面的代碼中,我們使用了下面的代碼來發送請求:
它傳回一個qnetworkreply對象,這個後面再講。我們隻需知道隻要發送請求成功,它就會下載下傳資料。而當資料下載下傳完成後,manager會發出finished()信号,我們關聯了該信号:
也就是說,當下載下傳資料結束時,就會執行replyfinished()函數。在這個函數中我們對接收的資料進行處理:
qtextcodec *codec = qtextcodec::codecforname("utf8");
qstring all = codec->tounicode(reply->readall());
ui->textbrowser->settext(all);
這裡,為了能顯示下載下傳的網頁中的中文,我們使用了qtextcodec 類對象,應用utf8編碼。使用reply->readall()函數就可以将下載下傳的所有資料讀出。然後,我們在textbrowser中将資料顯示出來。當reply對象已經完成了它的功能時,我們需要将它釋放,就是最後一條代碼:
reply->deletelater();
通過上面的例子可以看到,qt中編寫基于http協定的程式是十分簡單的,隻有十幾行代碼。不過,一般我們下載下傳檔案都想要看到下載下傳進度。下面我們就更改上面的程式,讓它可以下載下傳任意的檔案,并且顯示下載下傳進度。
1.進入設計模式,删除以前的text browser部件,然後拖入一個line edit,一個label,一個progress
bar和一個push button,設計界面如下圖所示。
2. 在寫代碼之前,我們先介紹一下整個程式執行的流程:開始我們先讓進度條隐藏。當我們在line edit中輸入下載下傳位址,點選下載下傳按鈕後,我們應用輸入的下載下傳位址,獲得檔案名,在磁盤上建立一個檔案,用于儲存下載下傳的資料,然後進行連結,并顯示進度條。在下載下傳過程中,我們将每次獲得的資料都寫入檔案中,并更新進度條,在接收完檔案後,我們重新隐藏進度條,并做一些清理工作。根據這個思路,我們開始代碼的編寫。
3.到mainwindow.h中,首先添加public函數聲明:
void startrequest(qurl url); //請求連結
然後添加幾個private變量和對象定義:
qnetworkreply *reply;
qurl url; //存儲網絡位址
qfile *file; //檔案指針
最後到private slots中,删除前面的replyfinished(qnetworkreply *)槽聲明,并添加如下代碼:
void on_pushbutton_clicked(); //下載下傳按鈕的單擊事件槽函數
void httpfinished(); //完成下載下傳後的處理
void httpreadyread(); //接收到資料時的處理
void updatedatareadprogress(qint64, qint64); //更新進度條
4. 下面到mainwindow.cpp檔案中,将前面在構造函數中添加的内容删除,然後添加如下代碼:
manager = new qnetworkaccessmanager(this);
ui->progressbar->hide();
我們在構造函數中先隐藏進度條。等開始下載下傳時再顯示它。
5. 下面将前面程式中添加的replyfinished()函數的定義删除,然後添加新的函數的定義。先添加網絡請求函數的實作:
void mainwindow::startrequest(qurl url)
reply = manager->get(qnetworkrequest(url));
connect(reply, signal(readyread()), this, slot(httpreadyread()));
connect(reply, signal(downloadprogress(qint64, qint64)),
this, slot(updatedatareadprogress(qint64, qint64)));
connect(reply, signal(finished()), this, slot(httpfinished()));
這裡使用了get()函數來發送網絡請求,然後進行了qnetworkreply對象的幾個信号和自定義槽的關聯。其中readyread()信号繼承自qiodevice類,每當有新的資料可以讀取時,都會發射該信号;每當網絡請求的下載下傳進度更新時都會發射downloadprogress()信号,它用來更新進度條;每當應答處理結束時,都會發射finished()信号,該信号與前面程式中qnetworkaccessmanager類的finished()信号作用相同,隻不過是發送者不同,參數也不同而已。下面添加幾個槽的定義。
void mainwindow::httpreadyread()
if (file) file->write(reply->readall());
這裡先判斷是否建立了檔案,如果是,則讀取傳回的所有資料,然後寫入到檔案。該檔案是在後面的“下載下傳”按鈕單擊信号槽中建立并打開的。
void mainwindow::updatedatareadprogress(qint64 bytesread, qint64 totalbytes)
ui->progressbar->setmaximum(totalbytes);
ui->progressbar->setvalue(bytesread);
這裡設定了一下進度條的最大值和目前值。
void mainwindow::httpfinished()
ui->progressbar->hide();
file->flush();
file->close();
reply = 0;
delete file;
file = 0;
當完成下載下傳後,重新隐藏進度條,然後删除reply和file對象。下面是“下載下傳”按鈕的單擊信号的槽:
void mainwindow::on_pushbutton_clicked()
url = ui->lineedit->text();
qfileinfo info(url.path());
qstring filename(info.filename());
if (filename.isempty()) filename = "index.html";
file = new qfile(filename);
if(!file->open(qiodevice::writeonly))
{
qdebug() << "file open error";
delete file;
file = 0;
return;
}
startrequest(url);
ui->progressbar->setvalue(0);
ui->progressbar->show();
這裡使用要下載下傳的檔案名建立了本地檔案,然後使用輸入的url進行了網絡請求,并顯示進度條。
完成後,可以嘗試輸入一個檔案的下載下傳位址,比如這裡輸入了《qt creator快速入門》一書在百度網盤上的位址,效果如下圖所示。
7.最後,可以去項目編譯生成的檔案目錄中檢視下載下傳的檔案(我這裡是e:\http-build-桌面-debug),可以看到下載下傳的檔案,如下圖所示。
結語
http應用的内容就講到這裡,可以看到它是很容易的,也不需要大家了解太多的http的原理知識。關于相關的類的其他使用,也可以檢視其幫助文檔。在上面的例子中,我們隻是為了講解知識,是以程式不是很完善,對于一個真正的工程,還是需要注意更多其他細節的,大家可以檢視一下qt示範程式http
client的源代碼。
涉及到的源碼:
kb, 下載下傳次數: 14)