Qt实现 Http网络在线下载程序(支持断点续传功能)
发布日期:2021-09-25 21:40:45 浏览次数:8 分类:技术文章

本文共 3574 字,大约阅读时间需要 11 分钟。

目录


开发过程中遇到了一些坑,花了半天时间搞。出现了很多理论上不应该出现的bug。

做这个的目的,主要是为了巩固一下对Qt网络部分接口的使用,以及http协议的记忆。

思路主要是,解析URL——>获取响应头——>获取响应状态码——>请求下载——>回读当前文件字节数进行断点续传。

需要注意,访问https前,需要添加libcrypto-1_1.dll与libssl-1_1.dll到Qt\5.14.0\mingw73_32\bin或者exe目录下。

以上DLL下载地址:

需要注意一下32位和64位,应下载与自己Qt编译器位数一致的版本。下载好后直接安装,然后到安装目录拷贝即可。

一、gitHub地址

 

二、功能

支持输入url网址进行在线下载,具备断点续传功能。

后期扩展:结合qml树列表与多线程,模拟出迅雷的下载效果。

 

三、目前存在的问题

QEventLoop *loop = new QEventLoop;connect(m_netWorkManager, SIGNAL(finished(QNetworkReply*)), loop, SLOT(quit()));m_reply = m_netWorkManager->get(request);loop->exec();

通过以上get访问到需要跳转的url时,速度明显快于不需要跳转的。具体原因还不清楚。

 

四、界面效果

粗略的绘制了一下界面,比较丑,主要以实现效果为主。

 

五、主要代码

启动下载:

void Http::startDownLoad(const QString &url){    m_url = url;    if(m_url.isEmpty()) return;    if(!m_IsDownloading)    {        //获取请求头        QNetworkRequest request;        QUrl url = QUrl(m_url);        request.setUrl(url);        m_fileName = url.fileName();        qDebug()<<"fileName = "<
head(request); m_state = requestHead; getCurrentFileSize(); connect(m_reply,SIGNAL(finished()),this,SLOT(onfinishedRequest())); }}

通过setUrl来装载我们请求的地址,随后获取请求头,请求结束后,进入槽函数做处理。

暂停下载:

void Http::stopDownLoad(){    if(m_reply == nullptr) return;    disconnect(m_reply,SIGNAL(readyRead()),this,SLOT(onReadyRead()));    disconnect(m_reply,SIGNAL(error(QNetworkReply::NetworkError)),this,SLOT(onError(QNetworkReply::NetworkError)));    disconnect(m_reply,SIGNAL(finished()),this,SLOT(onfinishedRequest()));    m_reply->abort();    m_reply->deleteLater();    m_file.close();    getCurrentFileSize();    m_IsDownloading = false;}

暂停下载主要是断开信号槽的连接,然后释放资源和关闭文件操作符。

文件大小回读:

void Http::getCurrentFileSize(){    QFileInfo fileInfo(m_fileName);    if(fileInfo.exists())    {        m_currentLoadedBytes = fileInfo.size();    }    else    {        m_currentLoadedBytes = 0;    }}

通过QFileInfo类提供的size()接口,获取文件当前的字节大小。

槽函数onfinishedRequest():

void Http::onfinishedRequest(){    if(m_reply==nullptr) return;    if(m_state == requestHead)    {               m_fileSize = m_reply->rawHeader("Content-Length").toInt();        qDebug()<<"m_fileSize = "<
get(request); loop->exec(); //获取状态码 m_statusCode = m_reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); qDebug()<<"statusCode="<
attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl(); request.setUrl(realUrl); } else { return; } QString downLoadSize = QString::number(m_fileSize); QString selectSize = QString("bytes=%1-%2").arg(m_currentLoadedBytes).arg(downLoadSize); request.setRawHeader("Range",selectSize.toLatin1()); m_reply = m_netWorkManager->get(request); connect(m_reply,SIGNAL(finished()),this,SLOT(onfinishedRequest())); connect(m_reply,SIGNAL(readyRead()),this,SLOT(onReadyRead())); connect(m_reply,SIGNAL(error(QNetworkReply::NetworkError)),this,SLOT(onError(QNetworkReply::NetworkError)));}

这里需要注意的是做了一个转调功能,因为有些资源的实际下载地址并不是当前所给的Url。当返回302的时候,说明需要获取背后正确的下载地址。

槽函数onReadyRead():

void Http::onReadyRead(){    if(m_reply==nullptr) return;    if(!m_file.isOpen())    {        m_file.setFileName(m_fileName);        m_file.open(QIODevice::WriteOnly|QIODevice::Append);    }    m_file.write(m_reply->readAll());    m_downLoadedBytes =m_file.size();    emit fileDownloadProgress(m_downLoadedBytes, m_fileSize);    if(m_file.size() == m_fileSize)    {        qDebug()<<"download finished!";        stopDownLoad();    }}

将接收到的数据,写入文件中,并且将当前下载字节数通过信号槽发送出去,提供给进度条对话框使用。

当下载的字节总大小等于请求时服务器返回过来的文件大小时,就认为下载结束。

当然,更严谨的做法是再计算文件的MD5码,与服务器回传的MD5码进行比较,以确保下载的是正确的文件。

转载地址:https://blog.csdn.net/c_shell_python/article/details/106294014 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:基于原生c++代码实现的Http下载程序
下一篇:批处理之bat脚本删除指定文件外的所有文件与文件夹

发表评论

最新留言

逛到本站,mark一下
[***.202.152.39]2024年04月06日 23时29分10秒