閱讀651 返回首頁    go 阿裏雲 go 技術社區[雲棲]


[Qt教程] 第32篇 網絡(二)HTTP

[Qt教程] 第32篇 網絡(二)HTTP

樓主
 發表於 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部件。效果如下圖所示。

32-1.jpg

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("https://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>
       下麵運行程序,效果如下圖所示。

32-2.jpg
       
這裏再將整個過程簡答敘述一遍:上麵實現了最簡單的應用HTTP協議下載網頁的功能。QNetworkAccessManager類用於發送網絡請求和接受回複,具體來說,它是用QNetworkRequest 類來管理請求,QNetworkReply類進行接收回複,並對數據進行處理。
在上麵的代碼中,我們使用了下麵的代碼來發送請求:

manager->get(QNetworkRequest(QUrl("https://www.qter.org")));

它返回一個QNetworkReply對象,這個後麵再講。我們隻需知道隻要發送請求成功,它就會下載數據。而當數據下載完成後,manager會發出finished()信號,我們關聯了該信號:

connect(manager, SIGNAL(finished(QNetworkReply*)),
this,SLOT(replyFinished(QNetworkReply*)));

也就是說,當下載數據結束時,就會執行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,設計界麵如下圖所示。

32-3.jpg

2. 
在寫代碼之前,我們先介紹一下整個程序執行的流程:開始我們先讓進度條隱藏。當我們在Line Edit中輸入下載地址,點擊下載按鈕後,我們應用輸入的下載地址,獲得文件名,在磁盤上新建一個文件,用於保存下載的數據,然後進行鏈接,並顯示進度條。在下載過程中,我們將每次獲得的數據都寫入文件中,並更新進度條,在接收完文件後,我們重新隱藏進度條,並做一些清理工作。根據這個思路,我們開始代碼的編寫。

3.
mainwindow.h中,首先添加public函數聲明:
void startRequest(QUrl url); //請求鏈接

然後添加幾個private變量和對象定義:
QNetworkReply *reply;
QUrl url;   //存儲網絡地址
QFile *file;  //文件指針

最後到private slots中,刪除前麵的
replyFinished(QNetworkReply *)槽聲明,並添加如下代碼:
private slots:
    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->deleteLater();
    reply = 0;
    delete file;
    file = 0;
}
        
當完成下載後,重新隱藏進度條,然後刪除replyfile對象。下麵是“下載”按鈕的單擊信號的槽:
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進行了網絡請求,並顯示進度條。

6.
下麵運行程序,我們先輸入
www.yafeilinux.com的網址,下麵一個網頁。效果如下圖所示。

32-4.jpg 

完成後,可以嚐試輸入一個文件的下載地址,比如這裏輸入了《Qt Creator快速入門》一書在百度網盤上的地址,效果如下圖所示。

32-5.jpg

7.
最後,可以去項目編譯生成的文件目錄中查看下載的文件(我這裏是E:\http-build-桌麵-Debug),可以看到下載的文件,如下圖所示。

32-6.jpg


結語


HTTP
應用的內容就講到這裏,可以看到它是很容易的,也不需要大家了解太多的HTTP的原理知識。關於相關的類的其他使用,也可以查看其幫助文檔。在上麵的例子中,我們隻是為了講解知識,所以程序不是很完善,對於一個真正的工程,還是需要注意更多其他細節的,大家可以查看一下Qt演示程序HTTP Client的源代碼。



涉及到的源碼:  http.zip (2.89 KB, 下載次數: 14) 

最後更新:2017-04-03 14:54:11

  上一篇:go 在頁麵中 js 獲取光標/鼠標的坐標,獲取光標的的像素坐標
  下一篇:go DirectDraw讀書筆記