spark-qt-research/MultiplethreadDownload/downloadworker.cpp
2021-02-16 20:18:33 +08:00

184 lines
4.9 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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