天天看點

QT HTTP接收多個資料包生成圖檔

看了看電腦右上角的時間,2017就要徹底流逝了。再瞅了瞅本月的文章數,天啦,隻有一篇,近一個月沒有時間學習,沒有時間寫文章,沒有時間休息,總之就是沒時間……好強烈的罪惡感,趕緊抓住最後的幾個小時,補上一文!

我們知道簡單的HTTP請求可以一次傳回結果,但對于一些資料量較大的情況,則要分多次傳回。

QNetworkAccessManager下的QNetworkReply有readyRead信号,一旦該信号産生,就可以讀取相應的資料并寫入檔案中。

對于較大的檔案,比如圖檔,一個http請求需要分多個資料包傳回結果最後才能得到完整的集合。

好在有QNetworkReply::finished。該信号提示我們不會再有資料更新了,此時就可以關閉檔案流,結束資料存儲。

如下:

new QNetworkRequest ();

    manager = new QNetworkAccessManager(this);

    request->setUrl(QUrl("https://static.baydn.com/static/img/icon_head.png"));

    reply = manager->get(*request);

    connect(reply, SIGNAL(readyRead()), this, SLOT(slotReadyRead()));

    connect(reply, SIGNAL(error(QNetworkReply::NetworkError)),

          this, SLOT(slotError(QNetworkReply::NetworkError)));

    // SSL(Secure Sockets Layer 安全套接層), it encrypts data.

    connect(reply, SIGNAL(sslErrors(QList<QSslError>)),

            this, SLOT(slotSslErrors(QList<QSslError>)));

    connect(reply, SIGNAL(finished()), this, SLOT(slotFinished()));      

資料存儲函數:

void HttpManager::slotReadyRead()
{
    static int time = 0;
    QByteArray bytes = reply->readAll();
    QString url = reply->request().url().toString();
    int fd;
    if(searchFilesMap(url.toStdString())){  //if fd exist, we append data to local file.
        fd = filesMap[url.toStdString()];
        size_t ret = write(fd, bytes.toStdString().c_str(), bytes.size());
        if(ret <= 0){
            LOGDBG("write failed: %s", strerror(errno));
        }
    }
    else {  //if not exist, we. open and write.
        string path = getIncomLocalPicPath(url.toStdString());
        fd = open(path.c_str(), O_WRONLY | O_CREAT | O_TRUNC);
        if(fd == -1){
            LOGDBG("open failed, %s",strerror(errno));
            return ;
        }
        fchmod(fd, 0777);
        size_t ret = write(fd, bytes.toStdString().c_str(), bytes.size());
        if(ret <= 0){
            LOGDBG("write failed: %s", strerror(errno));
        }
        // add info to map
        filesMap[url.toStdString()] = fd;
    }

    LOGDBG("%d finished, fd: %d, url: %s",++time, fd, reply->request().url().toString().toStdString().c_str());
}      

結束函數:

關閉句柄并重命名。

void HttpManager::slotFinished()
{
    QString url = reply->request().url().toString();
    QByteArray bytes = reply->readAll();
    int fd = filesMap[url.toStdString()];
    close(fd);
    string f1;
    string f2;
    f1 = getIncomLocalPicPath(url.toStdString());
    f2 = getComLocalPicPath(url.toStdString());
    if(0 != rename(f1.c_str(),f2.c_str())){
        LOGDBG("rename failed: %s", strerror(errno));
    }
    LOGDBG("%d, finished.", fd);      
$ ./http_test 
[file: httpmanager.cpp, line: 152, funcName: slotReadyRead]  1 finished, fd: 19, url: https://static.baydn.com/static/img/icon_head.png
[file: httpmanager.cpp, line: 152, funcName: slotReadyRead]  2 finished, fd: 19, url: https://static.baydn.com/static/img/icon_head.png
[file: httpmanager.cpp, line: 152, funcName: slotReadyRead]  3 finished, fd: 19, url: https://static.baydn.com/static/img/icon_head.png
[file: httpmanager.cpp, line: 152, funcName: slotReadyRead]  4 finished, fd: 19, url: https://static.baydn.com/static/img/icon_head.png
[file: httpmanager.cpp, line: 152, funcName: slotReadyRead]  5 finished, fd: 19, url: https://static.baydn.com/static/img/icon_head.png
[file: httpmanager.cpp, line: 181, funcName: slotFinished]  19, finished.