完成并发下载的进度统计

This commit is contained in:
metanoia1989 2021-02-16 20:18:33 +08:00
parent 2d3d35f951
commit 54fa6ff3b6
4 changed files with 134 additions and 93 deletions

View File

@ -43,3 +43,52 @@ http://localhost:8080/
* https://sucdn.jerrywang.top/ * https://sucdn.jerrywang.top/
* https://store.deepinos.org.cn/ * https://store.deepinos.org.cn/
原来的单线程相关代码
```cpp
// 在处理下载进度的代码中,会一直检测下载是否取消
void Widget::updateDataReadProgress(qint64 bytesRead, qint64 totalBytes)
{
if(totalBytes <= 0) return;
download_list[nowDownload-1].setMax(10000); // 最大值
download_list[nowDownload-1].setValue((bytesRead*10000)/totalBytes); // 当前值
download_size=bytesRead;
if(download_list[nowDownload-1].close){ // 随时检测下载是否被取消
download_list[nowDownload-1].closeDownload();
httpFinished();
}
}
// 但是这里的 download_list[nowDownload-1].close 是在哪里修改的呢?
downloadlist download_list[LIST_MAX];
download_list 是一个下载进度组件,维持动画的,还不错。
// 星火商店记录下载进度的代码
void Widget::updateDataReadProgress(qint64 bytesRead, qint64 totalBytes)
{
if(totalBytes <= 0) return;
download_list[nowDownload-1].setMax(10000); // 最大值
download_list[nowDownload-1].setValue((bytesRead*10000)/totalBytes); // 当前值
download_size=bytesRead;
if(download_list[nowDownload-1].close){ // 随时检测下载是否被取消
download_list[nowDownload-1].closeDownload();
httpFinished();
}
}
void Widget::httpFinished() // 完成下载
{
file->flush();
file->close();
reply->deleteLater();
reply = nullptr;
delete file;
file = nullptr;
isdownload=false;
isBusy=false;
}
```
然后那个多线程下载组件需要的几个功能点:
* 下载进度,以及下载速度记录
* 下载取消功能
* 读取设置,允许设置单线程下载 这个可以放到后面做,优先实现上面两个

View File

@ -5,6 +5,7 @@
#include <QNetworkRequest> #include <QNetworkRequest>
#include <QNetworkReply> #include <QNetworkReply>
#include <QDebug> #include <QDebug>
#include <QThread>
DownloadWorker::DownloadWorker(QObject *parent) DownloadWorker::DownloadWorker(QObject *parent)
{ {
@ -19,59 +20,55 @@ void DownloadWorker::setIdentifier(int identifier)
void DownloadWorker::setParamter(const QString &url, QPair<qint64, qint64> range, QFile *file) void DownloadWorker::setParamter(const QString &url, QPair<qint64, qint64> range, QFile *file)
{ {
this->url = url; this->url = url;
// this->range = range;
this->startPos = range.first; this->startPos = range.first;
this->endPos = range.second; this->endPos = range.second;
this->file = file; this->file = file;
} }
qint64 DownloadWorker::getReceivedPos()
{
return receivedPos;
}
void DownloadWorker::doWork() void DownloadWorker::doWork()
{ {
QNetworkAccessManager *mgr = new QNetworkAccessManager(this); mgr = new QNetworkAccessManager(this);
QNetworkRequest request; QNetworkRequest request;
request.setUrl(url); request.setUrl(url);
request.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true); request.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
request.setRawHeader("Range", QString("bytes=%1-%2").arg(startPos) request.setRawHeader("Range", QString("bytes=%1-%2").arg(startPos)
.arg(endPos).toLocal8Bit()); .arg(endPos).toLocal8Bit());
// QNetworkReply *reply = mgr->get(request);
// QNetworkReply *reply = mgr->get(request);
reply = mgr->get(request); reply = mgr->get(request);
// qDebug() << "开始下载数据:" << QString(" %1~%2 -> writePos Start %3")
// .arg(range.first).arg(range.second).arg(writePos);
qDebug() << "开始下载数据:" << QString(" %1~%2 -> writePos Start %3") qDebug() << "开始下载数据:" << QString(" %1~%2 -> writePos Start %3")
.arg(startPos).arg(endPos).arg(receivedPos); .arg(startPos).arg(endPos).arg(receivedPos);
// connect(reply, &QNetworkReply::readyRead, [reply, this](){ connect(reply, &QNetworkReply::errorOccurred, [this](QNetworkReply::NetworkError error){
//// qDebug() << "测试是否触发,午安啦啦啦"; if (error != QNetworkReply::NoError) {
// QByteArray data = reply->readAll(); qDebug() << "出错了:" << reply->errorString();
// qDebug() << "获取到了数据" << " " << data.size(); }
// emit resultReady(identifier, data); });
// });
// connect(reply, &QNetworkReply::errorOccurred, [reply](QNetworkReply::NetworkError error){
// if (error != QNetworkReply::NoError) {
// qDebug() << "出错了:" << reply->errorString();
// }
// });
connect(reply, &QNetworkReply::finished, mgr, &QNetworkAccessManager::deleteLater); connect(reply, &QNetworkReply::finished, mgr, &QNetworkAccessManager::deleteLater);
connect(reply, &QNetworkReply::finished, reply, &QNetworkReply::deleteLater); connect(reply, &QNetworkReply::finished, reply, &QNetworkReply::deleteLater);
connect(reply, &QNetworkReply::readyRead, this, &DownloadWorker::dataReady); connect(reply, &QNetworkReply::readyRead, this, &DownloadWorker::dataReady);
connect(reply, &QNetworkReply::finished, this, &DownloadWorker::slotFinish); 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() void DownloadWorker::dataReady()
{ {
qDebug() << QString("测试是否执行: %1 %2").arg(startPos).arg(receivedPos); qDebug() << QString("测试是否执行: %1 %2").arg(startPos).arg(receivedPos);
QByteArray data = reply->readAll(); QByteArray data = reply->readAll();
qDebug() << "获取到了数据" << " " << data.size(); file->seek(startPos + receivedPos);
// emit resultReady(identifier, data); file->write(data);
// auto controller = qobject_cast<DownloadController*>(parent()); receivedPos += data.size();
// QMetaObject::invokeMethod(controller, "handleResults", Qt::DirectConnection,
// Q_ARG(int, identifier), Q_ARG(QByteArray, data));
// QMetaObject::invokeMethod(controller, "handleResults", Qt::QueuedConnection,
file->seek(startPos + receivedPos);
file->write(data);
qDebug() << QString("%1, %2, %3").arg(startPos).arg(receivedPos).arg(data.size());
receivedPos += data.size();
// Q_ARG(int, identifier), Q_ARG(QByteArray, data));
} }
void DownloadWorker::slotFinish() void DownloadWorker::slotFinish()
@ -79,23 +76,20 @@ void DownloadWorker::slotFinish()
file->flush(); file->flush();
qDebug() << "数据块下载完毕:" << QString(" %1~%2 -> writePos Start %3") qDebug() << "数据块下载完毕:" << QString(" %1~%2 -> writePos Start %3")
.arg(startPos).arg(endPos).arg(receivedPos); .arg(startPos).arg(endPos).arg(receivedPos);
emit workFinished();
}
void DownloadWorker::handleProcess(qint64, qint64)
{
emit this->downloadProcess();
} }
DownloadController::DownloadController(QObject *parent) DownloadController::DownloadController(QObject *parent)
{ {
this->threadNum = 4; this->threadNum = 4;
// 注册信号槽传递的数据类型
qRegisterMetaType<QPair<qint64, qint64>>("QPair<qint64, qint64>");
} }
DownloadController::~DownloadController()
{
}
void DownloadController::setFilename(QString filename) void DownloadController::setFilename(QString filename)
{ {
this->filename = filename; this->filename = filename;
@ -111,79 +105,79 @@ void DownloadController::setThreadNum(int threadNum)
*/ */
void DownloadController::startDownload(const QString &url, qint64 fileSize) void DownloadController::startDownload(const QString &url, qint64 fileSize)
{ {
finish = 0;
// 下载任务等分,计算每个线程的下载数据 // 下载任务等分,计算每个线程的下载数据
this->fileSize = fileSize;
qint64 segmentSize = fileSize / threadNum; qint64 segmentSize = fileSize / threadNum;
ranges.resize(threadNum); ranges.resize(threadNum);
// QVector<qint64> writePosList; QVector<qint64> receivedBytes;
writePosList.resize(threadNum); receivedBytes.resize(threadNum);
for (int i = 0; i < threadNum; i++) { for (int i = 0; i < threadNum; i++) {
ranges[i].first = i * segmentSize; ranges[i].first = i * segmentSize;
ranges[i].second = i * segmentSize + segmentSize - 1; ranges[i].second = i * segmentSize + segmentSize - 1;
writePosList[i] = ranges[i].first; receivedBytes[i] = 0;
} }
ranges[threadNum-1].second = fileSize; // 余数部分加入最后一个 ranges[threadNum-1].second = fileSize; // 余数部分加入最后一个
qDebug() << QString("查看分段下载:%1 %2").arg(ranges.size()).arg(writePosList.size());
// return;
// 打开文件 // 打开文件
file = new QFile; file = new QFile;
file->setFileName(filename); file->setFileName(filename);
if (file->exists()) if (file->exists())
file->remove(); file->remove();
if (!file->open(QIODevice::WriteOnly)) { if (!file->open(QIODevice::WriteOnly)) {
delete file;
file = nullptr;
emit errorOccur(file->errorString()); emit errorOccur(file->errorString());
return; return;
} }
file->resize(fileSize); file->resize(fileSize);
// 创建下载线程 // 创建下载线程
// qint64 bytesReceived = 0;
for(int i = 0; i < ranges.size(); i++) { 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); qDebug() << QString("第%1个下载请求%2-%3").arg(i).arg(ranges.at(i).first).arg(ranges.at(i).second);
auto worker = new DownloadWorker(this); auto worker = new DownloadWorker(this);
auto range = ranges.at(i); auto range = ranges.at(i);
worker->setIdentifier(i); worker->setIdentifier(i);
worker->setParamter(url, range, file); worker->setParamter(url, range, file);
// connect(worker, &DownloadWorker::resultReady, this, &DownloadController::handleResults); workers.append(worker);
connect(worker, &DownloadWorker::downloadProcess, this, &DownloadController::handleProcess);
connect(worker, &DownloadWorker::workFinished, this, &DownloadController::chunkDownloadFinish);
worker->doWork(); worker->doWork();
} }
} }
/**
* @brief
*/
void DownloadController::paruseDownload()
{
}
/** /**
* @brief * @brief
*/ */
void DownloadController::stopDownload() void DownloadController::stopDownload()
{ {
for(int i = 0; i < workers.size(); i++) {
workers.at(i)->doStop();
}
file->flush();
file->close();
delete file;
file = nullptr;
} }
/**
* @brief void DownloadController::handleProcess()
* @param identifier 线
* @param data
*/
void DownloadController::handleResults(int identifier, QByteArray data)
{ {
qDebug() << QString("测试哈哈哈: %1 --- %2").arg(writePosList.size()).arg(identifier); qint64 bytesReceived = 0;
QMutexLocker lock(&mutex); for(int i = 0; i < workers.size(); i++) {
qint64 writePos = writePosList.at(identifier); bytesReceived += workers.at(i)->getReceivedPos();
file->seek(writePos); }
file->write(data); qDebug() << QString("下载进度 %1-%2").arg(bytesReceived).arg(fileSize);
qDebug() << QString("%1, %2, %3").arg(writePos).arg(bytesReceived).arg(data.size()); emit downloadProcess(bytesReceived, fileSize);
writePos += data.size(); }
writePosList.replace(identifier, writePos);
bytesReceived += data.size(); void DownloadController::chunkDownloadFinish()
qDebug() << "已经下载了数据: " << bytesReceived; {
emit receivedProcess(bytesReceived); finish++;
if (finish == threadNum) {
emit downloadFinished();
}
} }

View File

@ -5,7 +5,6 @@
#include <QList> #include <QList>
#include <QFile> #include <QFile>
#include <QNetworkReply> #include <QNetworkReply>
#include <QMutex>
class DownloadWorker : public QObject class DownloadWorker : public QObject
{ {
@ -14,25 +13,29 @@ public:
explicit DownloadWorker(QObject *parent = nullptr); explicit DownloadWorker(QObject *parent = nullptr);
void setIdentifier(int identifier); void setIdentifier(int identifier);
void setParamter(const QString &url, QPair<qint64, qint64> range, QFile *flle); void setParamter(const QString &url, QPair<qint64, qint64> range, QFile *flle);
qint64 getReceivedPos();
public slots: public slots:
void doWork(); void doWork();
void doStop();
void dataReady(); void dataReady();
void slotFinish(); void slotFinish();
void handleProcess(qint64, qint64);
signals: signals:
void resultReady(int identifier, QByteArray data); void resultReady(int identifier, QByteArray data);
void testSignals(); void testSignals();
void workFinished();
void downloadProcess();
private: private:
int identifier; int identifier;
QString url; QString url;
// QPair<qint64, qint64> range;
qint64 startPos; qint64 startPos;
qint64 endPos; qint64 endPos;
qint64 receivedPos = 0; qint64 receivedPos = 0;
QNetworkReply *reply; QNetworkReply *reply;
QNetworkAccessManager *mgr;
QFile *file; QFile *file;
}; };
@ -41,30 +44,28 @@ class DownloadController : public QObject
Q_OBJECT Q_OBJECT
public: public:
explicit DownloadController(QObject *parent = nullptr); explicit DownloadController(QObject *parent = nullptr);
~DownloadController();
void setFilename(QString filename); void setFilename(QString filename);
void setThreadNum(int threadNum); void setThreadNum(int threadNum);
void startDownload(const QString &url, qint64 fileSize); void startDownload(const QString &url, qint64 fileSize);
void paruseDownload();
void stopDownload(); void stopDownload();
public slots: public slots:
void handleResults(int identifier, QByteArray data); void handleProcess();
// void handleTest(); void chunkDownloadFinish();
signals: signals:
void operate(const QString &url, const QPair<qint64, qint64> &downloadRange);
void errorOccur(const QString& msg); void errorOccur(const QString& msg);
void receivedProcess(qint64 number); void downloadProcess(qint64, qint64);
void downloadFinished();
private: private:
int threadNum; int threadNum;
QString filename; QString filename;
qint64 fileSize;
QVector<QPair<qint64, qint64>> ranges; QVector<QPair<qint64, qint64>> ranges;
QFile *file; QFile *file;
qint64 bytesReceived; QList<DownloadWorker*> workers;
QVector<qint64> writePosList; int finish = 0;
QMutex mutex;
}; };
#endif // FILEDOWNLOADWORKER_H #endif // FILEDOWNLOADWORKER_H

View File

@ -255,11 +255,8 @@ void Widget::multiDownloadWithQtConcurrent(const QString &url, qint64 fileSize,
void Widget::multiDownloadWithQThread(const QString& url, qint64 fileSize, const QString& filename, int threadCount) void Widget::multiDownloadWithQThread(const QString& url, qint64 fileSize, const QString& filename, int threadCount)
{ {
DownloadController download; DownloadController *download = new DownloadController(this);
download.setFilename(filename); download->setFilename(filename);
download.startDownload(url, fileSize); download->startDownload(url, fileSize);
connect(&download, &DownloadController::receivedProcess, [fileSize, this](int receivedNum){ connect(download, &DownloadController::downloadProcess, this, &Widget::download_progress_change);
int percent = receivedNum / fileSize;
ui->downProgressBar->setValue(percent);
});
} }