diff --git a/MultiplethreadDownload/REAMDE.md b/MultiplethreadDownload/REAMDE.md index f8e1ddd..55b34ad 100644 --- a/MultiplethreadDownload/REAMDE.md +++ b/MultiplethreadDownload/REAMDE.md @@ -43,3 +43,52 @@ http://localhost:8080/ * https://sucdn.jerrywang.top/ * 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; +} +``` + +然后那个多线程下载组件需要的几个功能点: +* 下载进度,以及下载速度记录 +* 下载取消功能 +* 读取设置,允许设置单线程下载 这个可以放到后面做,优先实现上面两个 \ No newline at end of file diff --git a/MultiplethreadDownload/downloadworker.cpp b/MultiplethreadDownload/downloadworker.cpp index fb2760c..58f46fb 100644 --- a/MultiplethreadDownload/downloadworker.cpp +++ b/MultiplethreadDownload/downloadworker.cpp @@ -5,6 +5,7 @@ #include #include #include +#include DownloadWorker::DownloadWorker(QObject *parent) { @@ -19,59 +20,55 @@ void DownloadWorker::setIdentifier(int identifier) void DownloadWorker::setParamter(const QString &url, QPair range, QFile *file) { this->url = url; -// this->range = range; this->startPos = range.first; this->endPos = range.second; this->file = file; } +qint64 DownloadWorker::getReceivedPos() +{ + return receivedPos; +} + void DownloadWorker::doWork() { - QNetworkAccessManager *mgr = new QNetworkAccessManager(this); + 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()); -// QNetworkReply *reply = mgr->get(request); -// QNetworkReply *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") .arg(startPos).arg(endPos).arg(receivedPos); -// connect(reply, &QNetworkReply::readyRead, [reply, this](){ -//// qDebug() << "测试是否触发,午安啦啦啦"; -// QByteArray data = reply->readAll(); -// 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::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(); - qDebug() << "获取到了数据" << " " << data.size(); -// emit resultReady(identifier, data); -// auto controller = qobject_cast(parent()); -// 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)); + 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() @@ -79,23 +76,20 @@ 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; - - // 注册信号槽传递的数据类型 - qRegisterMetaType>("QPair"); } -DownloadController::~DownloadController() -{ - -} - - void DownloadController::setFilename(QString filename) { this->filename = filename; @@ -111,79 +105,79 @@ void DownloadController::setThreadNum(int threadNum) */ void DownloadController::startDownload(const QString &url, qint64 fileSize) { + finish = 0; + // 下载任务等分,计算每个线程的下载数据 + this->fileSize = fileSize; qint64 segmentSize = fileSize / threadNum; ranges.resize(threadNum); -// QVector writePosList; - writePosList.resize(threadNum); + QVector receivedBytes; + receivedBytes.resize(threadNum); for (int i = 0; i < threadNum; i++) { ranges[i].first = i * segmentSize; ranges[i].second = i * segmentSize + segmentSize - 1; - writePosList[i] = ranges[i].first; + receivedBytes[i] = 0; } ranges[threadNum-1].second = fileSize; // 余数部分加入最后一个 - qDebug() << QString("查看分段下载:%1 %2").arg(ranges.size()).arg(writePosList.size()); -// return; // 打开文件 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); // 创建下载线程 -// qint64 bytesReceived = 0; 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 range = ranges.at(i); worker->setIdentifier(i); 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(); } } -/** - * @brief 暂停下载 - */ -void DownloadController::paruseDownload() -{ - -} - /** * @brief 停止下载 */ void DownloadController::stopDownload() { - + for(int i = 0; i < workers.size(); i++) { + workers.at(i)->doStop(); + } + file->flush(); + file->close(); + delete file; + file = nullptr; } -/** - * @brief 写入响应数据 - * @param identifier 线程编号 - * @param data 请求数据 - */ -void DownloadController::handleResults(int identifier, QByteArray data) + +void DownloadController::handleProcess() { - qDebug() << QString("测试哈哈哈: %1 --- %2").arg(writePosList.size()).arg(identifier); - QMutexLocker lock(&mutex); - qint64 writePos = writePosList.at(identifier); - file->seek(writePos); - file->write(data); - qDebug() << QString("%1, %2, %3").arg(writePos).arg(bytesReceived).arg(data.size()); - writePos += data.size(); - writePosList.replace(identifier, writePos); - bytesReceived += data.size(); - qDebug() << "已经下载了数据: " << bytesReceived; - emit receivedProcess(bytesReceived); + 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(); + } } diff --git a/MultiplethreadDownload/downloadworker.h b/MultiplethreadDownload/downloadworker.h index ea81615..8a7027a 100644 --- a/MultiplethreadDownload/downloadworker.h +++ b/MultiplethreadDownload/downloadworker.h @@ -5,7 +5,6 @@ #include #include #include -#include class DownloadWorker : public QObject { @@ -14,25 +13,29 @@ public: explicit DownloadWorker(QObject *parent = nullptr); void setIdentifier(int identifier); void setParamter(const QString &url, QPair range, QFile *flle); + qint64 getReceivedPos(); public slots: void doWork(); + void doStop(); void dataReady(); void slotFinish(); + void handleProcess(qint64, qint64); signals: void resultReady(int identifier, QByteArray data); void testSignals(); - + void workFinished(); + void downloadProcess(); private: int identifier; QString url; -// QPair range; qint64 startPos; qint64 endPos; qint64 receivedPos = 0; QNetworkReply *reply; + QNetworkAccessManager *mgr; QFile *file; }; @@ -41,30 +44,28 @@ class DownloadController : public QObject Q_OBJECT public: explicit DownloadController(QObject *parent = nullptr); - ~DownloadController(); void setFilename(QString filename); void setThreadNum(int threadNum); void startDownload(const QString &url, qint64 fileSize); - void paruseDownload(); void stopDownload(); public slots: - void handleResults(int identifier, QByteArray data); -// void handleTest(); + void handleProcess(); + void chunkDownloadFinish(); signals: - void operate(const QString &url, const QPair &downloadRange); void errorOccur(const QString& msg); - void receivedProcess(qint64 number); + void downloadProcess(qint64, qint64); + void downloadFinished(); private: int threadNum; QString filename; + qint64 fileSize; QVector> ranges; QFile *file; - qint64 bytesReceived; - QVector writePosList; - QMutex mutex; + QList workers; + int finish = 0; }; #endif // FILEDOWNLOADWORKER_H diff --git a/MultiplethreadDownload/widget.cpp b/MultiplethreadDownload/widget.cpp index 6f93528..1e2efcf 100644 --- a/MultiplethreadDownload/widget.cpp +++ b/MultiplethreadDownload/widget.cpp @@ -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) { - DownloadController download; - download.setFilename(filename); - download.startDownload(url, fileSize); - connect(&download, &DownloadController::receivedProcess, [fileSize, this](int receivedNum){ - int percent = receivedNum / fileSize; - ui->downProgressBar->setValue(percent); - }); + DownloadController *download = new DownloadController(this); + download->setFilename(filename); + download->startDownload(url, fileSize); + connect(download, &DownloadController::downloadProcess, this, &Widget::download_progress_change); }