2021-02-16 00:25:54 +08:00
|
|
|
|
#include "downloadworker.h"
|
|
|
|
|
#include <QIODevice>
|
|
|
|
|
#include <QEventLoop>
|
|
|
|
|
#include <QNetworkAccessManager>
|
|
|
|
|
#include <QNetworkRequest>
|
|
|
|
|
#include <QNetworkReply>
|
|
|
|
|
#include <QDebug>
|
2021-02-16 20:18:33 +08:00
|
|
|
|
#include <QThread>
|
2021-02-16 00:25:54 +08:00
|
|
|
|
|
|
|
|
|
DownloadWorker::DownloadWorker(QObject *parent)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void DownloadWorker::setIdentifier(int identifier)
|
|
|
|
|
{
|
|
|
|
|
this->identifier = identifier;
|
|
|
|
|
}
|
|
|
|
|
|
2021-02-16 02:08:00 +08:00
|
|
|
|
void DownloadWorker::setParamter(const QString &url, QPair<qint64, qint64> range, QFile *file)
|
2021-02-16 00:25:54 +08:00
|
|
|
|
{
|
|
|
|
|
this->url = url;
|
2021-02-16 02:08:00 +08:00
|
|
|
|
this->startPos = range.first;
|
|
|
|
|
this->endPos = range.second;
|
|
|
|
|
this->file = file;
|
2021-02-16 00:25:54 +08:00
|
|
|
|
}
|
|
|
|
|
|
2021-02-16 20:18:33 +08:00
|
|
|
|
qint64 DownloadWorker::getReceivedPos()
|
|
|
|
|
{
|
|
|
|
|
return receivedPos;
|
|
|
|
|
}
|
|
|
|
|
|
2021-02-16 00:25:54 +08:00
|
|
|
|
void DownloadWorker::doWork()
|
|
|
|
|
{
|
2021-02-16 20:18:33 +08:00
|
|
|
|
mgr = new QNetworkAccessManager(this);
|
2021-02-16 00:25:54 +08:00
|
|
|
|
QNetworkRequest request;
|
|
|
|
|
request.setUrl(url);
|
|
|
|
|
request.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
|
2021-02-16 02:08:00 +08:00
|
|
|
|
request.setRawHeader("Range", QString("bytes=%1-%2").arg(startPos)
|
|
|
|
|
.arg(endPos).toLocal8Bit());
|
2021-02-16 00:25:54 +08:00
|
|
|
|
reply = mgr->get(request);
|
|
|
|
|
qDebug() << "开始下载数据:" << QString(" %1~%2 -> writePos Start %3")
|
2021-02-16 02:08:00 +08:00
|
|
|
|
.arg(startPos).arg(endPos).arg(receivedPos);
|
2021-02-16 20:18:33 +08:00
|
|
|
|
connect(reply, &QNetworkReply::errorOccurred, [this](QNetworkReply::NetworkError error){
|
|
|
|
|
if (error != QNetworkReply::NoError) {
|
|
|
|
|
qDebug() << "出错了:" << reply->errorString();
|
|
|
|
|
}
|
|
|
|
|
});
|
2021-02-16 00:25:54 +08:00
|
|
|
|
connect(reply, &QNetworkReply::finished, mgr, &QNetworkAccessManager::deleteLater);
|
|
|
|
|
connect(reply, &QNetworkReply::finished, reply, &QNetworkReply::deleteLater);
|
|
|
|
|
connect(reply, &QNetworkReply::readyRead, this, &DownloadWorker::dataReady);
|
2021-02-16 02:08:00 +08:00
|
|
|
|
connect(reply, &QNetworkReply::finished, this, &DownloadWorker::slotFinish);
|
2021-02-16 20:18:33 +08:00
|
|
|
|
connect(reply, &QNetworkReply::downloadProgress, this, &DownloadWorker::handleProcess);
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void DownloadWorker::doStop()
|
|
|
|
|
{
|
|
|
|
|
reply->deleteLater();
|
|
|
|
|
reply = nullptr;
|
|
|
|
|
mgr->deleteLater();
|
|
|
|
|
mgr = nullptr;
|
2021-02-16 00:25:54 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void DownloadWorker::dataReady()
|
|
|
|
|
{
|
2021-02-16 20:18:33 +08:00
|
|
|
|
qDebug() << QString("测试是否执行: %1 %2").arg(startPos).arg(receivedPos);
|
|
|
|
|
QByteArray data = reply->readAll();
|
|
|
|
|
file->seek(startPos + receivedPos);
|
|
|
|
|
file->write(data);
|
|
|
|
|
receivedPos += data.size();
|
2021-02-16 02:08:00 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void DownloadWorker::slotFinish()
|
|
|
|
|
{
|
|
|
|
|
file->flush();
|
|
|
|
|
qDebug() << "数据块下载完毕:" << QString(" %1~%2 -> writePos Start %3")
|
|
|
|
|
.arg(startPos).arg(endPos).arg(receivedPos);
|
2021-02-16 20:18:33 +08:00
|
|
|
|
emit workFinished();
|
2021-02-16 00:25:54 +08:00
|
|
|
|
}
|
|
|
|
|
|
2021-02-16 20:18:33 +08:00
|
|
|
|
void DownloadWorker::handleProcess(qint64, qint64)
|
2021-02-16 00:25:54 +08:00
|
|
|
|
{
|
2021-02-16 20:18:33 +08:00
|
|
|
|
emit this->downloadProcess();
|
2021-02-16 00:25:54 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2021-02-16 20:18:33 +08:00
|
|
|
|
DownloadController::DownloadController(QObject *parent)
|
|
|
|
|
{
|
|
|
|
|
this->threadNum = 4;
|
2021-02-16 00:25:54 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void DownloadController::setFilename(QString filename)
|
|
|
|
|
{
|
|
|
|
|
this->filename = filename;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void DownloadController::setThreadNum(int threadNum)
|
|
|
|
|
{
|
|
|
|
|
this->threadNum = threadNum;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief 开始下载
|
|
|
|
|
*/
|
|
|
|
|
void DownloadController::startDownload(const QString &url, qint64 fileSize)
|
|
|
|
|
{
|
2021-02-16 20:18:33 +08:00
|
|
|
|
finish = 0;
|
|
|
|
|
|
2021-02-16 00:25:54 +08:00
|
|
|
|
// 下载任务等分,计算每个线程的下载数据
|
2021-02-16 20:18:33 +08:00
|
|
|
|
this->fileSize = fileSize;
|
2021-02-16 00:25:54 +08:00
|
|
|
|
qint64 segmentSize = fileSize / threadNum;
|
|
|
|
|
ranges.resize(threadNum);
|
2021-02-16 20:18:33 +08:00
|
|
|
|
QVector<qint64> receivedBytes;
|
|
|
|
|
receivedBytes.resize(threadNum);
|
2021-02-16 00:25:54 +08:00
|
|
|
|
for (int i = 0; i < threadNum; i++) {
|
|
|
|
|
ranges[i].first = i * segmentSize;
|
|
|
|
|
ranges[i].second = i * segmentSize + segmentSize - 1;
|
2021-02-16 20:18:33 +08:00
|
|
|
|
receivedBytes[i] = 0;
|
2021-02-16 00:25:54 +08:00
|
|
|
|
}
|
|
|
|
|
ranges[threadNum-1].second = fileSize; // 余数部分加入最后一个
|
|
|
|
|
|
|
|
|
|
// 打开文件
|
2021-02-16 02:08:00 +08:00
|
|
|
|
file = new QFile;
|
|
|
|
|
file->setFileName(filename);
|
|
|
|
|
if (file->exists())
|
|
|
|
|
file->remove();
|
|
|
|
|
if (!file->open(QIODevice::WriteOnly)) {
|
2021-02-16 20:18:33 +08:00
|
|
|
|
delete file;
|
|
|
|
|
file = nullptr;
|
2021-02-16 02:08:00 +08:00
|
|
|
|
emit errorOccur(file->errorString());
|
2021-02-16 00:25:54 +08:00
|
|
|
|
return;
|
|
|
|
|
}
|
2021-02-16 02:08:00 +08:00
|
|
|
|
file->resize(fileSize);
|
2021-02-16 00:25:54 +08:00
|
|
|
|
|
|
|
|
|
// 创建下载线程
|
|
|
|
|
for(int i = 0; i < ranges.size(); i++) {
|
2021-02-16 20:18:33 +08:00
|
|
|
|
qDebug() << QString("第%1个下载请求:%2-%3").arg(i).arg(ranges.at(i).first).arg(ranges.at(i).second);
|
2021-02-16 00:25:54 +08:00
|
|
|
|
auto worker = new DownloadWorker(this);
|
|
|
|
|
auto range = ranges.at(i);
|
|
|
|
|
worker->setIdentifier(i);
|
2021-02-16 02:08:00 +08:00
|
|
|
|
worker->setParamter(url, range, file);
|
2021-02-16 20:18:33 +08:00
|
|
|
|
workers.append(worker);
|
|
|
|
|
connect(worker, &DownloadWorker::downloadProcess, this, &DownloadController::handleProcess);
|
|
|
|
|
connect(worker, &DownloadWorker::workFinished, this, &DownloadController::chunkDownloadFinish);
|
2021-02-16 00:25:54 +08:00
|
|
|
|
worker->doWork();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief 停止下载
|
|
|
|
|
*/
|
|
|
|
|
void DownloadController::stopDownload()
|
|
|
|
|
{
|
2021-02-16 20:18:33 +08:00
|
|
|
|
for(int i = 0; i < workers.size(); i++) {
|
|
|
|
|
workers.at(i)->doStop();
|
|
|
|
|
}
|
|
|
|
|
file->flush();
|
|
|
|
|
file->close();
|
|
|
|
|
delete file;
|
|
|
|
|
file = nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
2021-02-16 00:25:54 +08:00
|
|
|
|
|
2021-02-16 20:18:33 +08:00
|
|
|
|
void DownloadController::handleProcess()
|
|
|
|
|
{
|
|
|
|
|
qint64 bytesReceived = 0;
|
|
|
|
|
for(int i = 0; i < workers.size(); i++) {
|
|
|
|
|
bytesReceived += workers.at(i)->getReceivedPos();
|
|
|
|
|
}
|
|
|
|
|
qDebug() << QString("下载进度 %1-%2").arg(bytesReceived).arg(fileSize);
|
|
|
|
|
emit downloadProcess(bytesReceived, fileSize);
|
2021-02-16 00:25:54 +08:00
|
|
|
|
}
|
|
|
|
|
|
2021-02-16 20:18:33 +08:00
|
|
|
|
void DownloadController::chunkDownloadFinish()
|
2021-02-16 00:25:54 +08:00
|
|
|
|
{
|
2021-02-16 20:18:33 +08:00
|
|
|
|
finish++;
|
|
|
|
|
if (finish == threadNum) {
|
|
|
|
|
emit downloadFinished();
|
|
|
|
|
}
|
2021-02-16 00:25:54 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|