Qt 之 HTTP 请求 多线程分块下载——上(获取下载文件大小)

简述

在 Qt 之 HTTP 请求下载(支持断点续传) 文章中我们使用Qt 的方法进行HTTP 请求下载文件,同时能够断点续传,本篇文章是这一篇文章的续篇。

我们一般在网上下载软件、电影、文件等,大都是使用迅雷下载,因为迅雷下载相对而言较快。在我们日常生活中,使用迅雷下载大文件时,非常占网速,甚至会占用整个家庭局域网的带宽。有时候浏览器都打不开网页,但是迅雷有限速功能,能够保护正常上网。下面看一张图。

Qt 之 HTTP 请求 多线程分块下载——上(获取下载文件大小)_第1张图片

这是最新的迅雷9设置界面,我们看到画圈的地方,这里有一个原始地址线程数,默认是5,范围为1-10,也就是迅雷将一个下载任务分成了5个线程分别进行下载,5个线程相对一个线程而言,资源的抢占的相对较多,下载速度相对较快。

难道说线程越多,下载速度越快吗?

不一定,因为下载速度还是看网络的最大带宽的,最大下载速度不可能超过宽带运营商提供的最大带宽(还有就是本地电脑的网卡),但是多个线程相对一个线程而言,总体的速度肯定会有所提升。就好比下面这一张图,我们可以将每个矩形看做一根管子,水从上面红色的管子流下,绿色的管子为本地电脑网卡,一般情况下网卡为百兆网卡,相对网络带宽而言,这根绿色的管子相对粗一些,所以电脑网卡一般情况下不会限制网速。再看下面棕色的管子,这里表示浏览器等一些其他软件所占用的网速,而蓝色的管子则为迅雷下载占用的网速,对比左右两个图,可以看出3根管子的水流量 >= 1根管子的水流量也就是说线程越多抢占的资源相对较多

Qt 之 HTTP 请求 多线程分块下载——上(获取下载文件大小)_第2张图片

线程是越多越好吗?

不一定,因为红色的管子的半径是固定的,即水流量是一定的,而如果不断增加下面蓝色的管子,这样每根管子的水流量就会相对减少。而创建的管子越多,必然会消耗更多的资源,所以并不是线程越多越好。线程要控制在一定的范围内,就迅雷而言,就将一个任务的线程控制在1~10范围内。


我们在使用Qt 的方法进行HTTP进行下载时,可以先对文件进行分块,然后对每一块创建一个线程进行下载,上面也讲述了多线程分块下载的好处,但是线程的数目需要自己控制好,下面我们先讲述如何用HTTP请求一个文件的总大小。

代码之路

qint64 getFileTotalSize(QString url, int tryTimes)
{
    qint64 size = -1;

    if (tryTimes <= 0)
    {
        tryTimes = 1;
    }

    do 
    {
        QNetworkAccessManager manager;
        // 事件循环,等待请求文件头信息结束;
        QEventLoop loop;
        // 超时,结束事件循环;
        QTimer timer;

        //发出请求,获取文件地址的头部信息;
        QNetworkReply *reply = manager.head(QNetworkRequest(url));
        if (!reply)
            continue;

        connect(reply, SIGNAL(finished()), &loop, SLOT(quit()));
        connect(&timer, SIGNAL(timeout()), &loop, SLOT(quit()));

        timer.start(2000);
        loop.exec();

        if (reply->error() != QNetworkReply::NoError)
        {
            qDebug() << reply->errorString();
            continue;
        }
        if (reply->error() != QNetworkReply::NoError)
        {
            // 请求发生错误;
            qDebug() << reply->errorString();
            continue;
        }
        else if (!timer.isActive())
        {
            // 请求超时超时,未获取到文件信息;
            qDebug() << "Request Timeout";
            continue;
        }
        timer.stop();

        QVariant var = reply->header(QNetworkRequest::ContentLengthHeader);
        size = var.toLongLong();
        reply->deleteLater();
        break;
    } while (tryTimes--);

    return size;
}

简单分析

上述提供了一个方法来通过HTTP请求获取到下载文件的大小,因为我们要对一个文件进行分块下载,那么首先肯定是要知道文件的大小,要不然怎么分块呢。

qint64 getFileTotalSize(QString url, int tryTimes)

第一个参数为下载文件的url,第二个参数为请求的次数,因为可能某种原因会导致请求失败(比如当前网络不是很好,或者文件服务器繁忙),所以做了三次尝试,尽可能保证请求成功。

对于请求次数首先要进行判断,防止次数为负数或者零。在do-while循环中进行请求文件大小。

这里我们使用了Qt中的事件循环来等待文件大小的请求结束,在文件请求完后结束事件循环。为了防止请求过慢,事件循环时间过长,这里加上了超时,超过2s结束事件循环,重新请求。(因为请求文件头信息在一般情况下耗时较短,除非网络不好或者文件服务器出了问题。具体超时时间按具体情况而定)

我们通过使用 reply->header(QNetworkRequest::ContentLengthHeader); 来获取文件头大小。参数具体可以看下图。

Qt 之 HTTP 请求 多线程分块下载——上(获取下载文件大小)_第3张图片


通过上面的叙述,我们获取到了要下载文件的大小,代码也很简单,但这只是第一步。下篇文章中将讲述如何分块,并创建多个线程分别下载各个文件块,同时能够保存下载信息,在程序第二次打开时继续下载。

你可能感兴趣的:(Qt,Qt,之,HTTP,请求)