一、高层网络协议类简介
  • Qt网络模块提供了一些类实现OSI 7层网络模型中高层的网络协议,如HTTP、FTP、SNMP等
  • 这些类主要为:
    • QNetworkRequest类:通过一个URL地址发起网络协议请求,也保存网络请求的信息,目前支持HTTP、FTP和局部文件URLs的下载或上传
    • NetworkAccessManager类:用于协调网络操作。在QNetworkRequest发起一个网络请求后,NetworkAccessManager负责发送网络请求,创建网络响应
    • QNetworkReply类:表示网络请求的相应。由NetworkAccessManager在发送一个网络请求后创建一个网络响应。QNetworkReply提供finished()、readyRead()、downloadProgress()可以监测网络响应的执行情况,执行相应的操作
      • QNetworkReply是QIODevice的子类,所以QNetworkReply支持流读写功能,也支持异步或同步工作
  • 想要使用那个类就添加相应的头文件,头文件名与类型相同
二、演示案例

第一步

  • 创建一个基于QMainWindow的项目,类名采取默认值。并设计界面
  • 在URL中输入一个网络文件URL,设置下载文件保存路径后,点击下载按钮开始下载文件到目录中。进度条(Progress Bar)表示文件下载进度

Qt:60---网络编程之HTTP通信(QNetworkRequest、QNetworkReply、NetworkAccessManager)_QNetworkReply

第二步

  • 构造函数
//只列出了自己手写的代码,系统的默认代码省略了
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QFile>
#include <QDir>
#include <QMessageBox>
#include <QUrl>
#include <QFileInfo>

class MainWindow : public QMainWindow
{
private:
    QNetworkAccessManager networkManager; //网络管理
    QNetworkReply *reply; //网络响应
    QFile *downloadedFile; //下载保存的临时文件    
private slots:
    //自定义槽函数
    void on_finished();
    void on_readyRead();
    void on_downloadProgress(qint64 bytesRead,qint64 totalBytes);
};

第三步

  • 缺省路径按钮的响应函数
//在当前应用程序目录下创建一个名为temp的临时目录
void MainWindow::on_btnDefaultPath_clicked()
{
    //获取当前应用程序的路径
    QString curPath=QDir::currentPath();
    
    //在当前目录下创建一个临时目录temp
    QDir dir(curPath);//打开当前应用程序的路径
    QString sub="temp";
    dir.mkdir(sub);
    
    ui->editPath->setText(curPath+"/"+sub+"/");
}

第四步

  • 下载按钮的响应函数
void MainWindow::on_btnDefaultPath_clicked()
{
    //获取当前应用程序的路径
    QString curPath=QDir::currentPath();

    //在当前目录下创建一个临时目录temp
    QDir dir(curPath);//打开当前应用程序的路径
    QString sub="temp";
    dir.mkdir(sub);

    ui->editPath->setText(curPath+"/"+sub+"/");
}

void MainWindow::on_btnDownload_clicked()
{
    //判断是否输入了URL
    QString urlSpec=ui->editURL->text().trimmed();
    if(urlSpec.isEmpty())
    {
        QMessageBox::information(this,QStringLiteral("错误"),QStringLiteral("请指定需要下载的文件URL"));
        return;
    }

    //将路径转为一个URL变量,判断输入的URL是否有误
    QUrl newUrl=QUrl::fromUserInput(urlSpec);
    if(!newUrl.isValid())
    {
        QMessageBox::information(this,QStringLiteral("错误"),QString(QStringLiteral("无效URL:%1\n错误信息:%2")).arg(urlSpec,newUrl.errorString()));
        return;
    }
    
    //判断是否打开了一个目录来保存下载的文件
    QString tempDir=ui->editPath->text().trimmed();
    if(tempDir.isEmpty())
    {
        QMessageBox::information(this,QStringLiteral("错误"),QStringLiteral("请指定下载文件保存目录"));
        return;
    }
    
    //如果想要下载的文件已经存在了,则先移除原先存在的文件
    QString fullFileName=tempDir+newUrl.fileName();
    if(QFile::exists(fullFileName))
        QFile::remove(fullFileName);
    
    //尝试打开要下载的文件
    downloadedFile=new QFile(fullFileName);
    if(!downloadedFile->open(QIODevice::WriteOnly))
    {
        QMessageBox::information(this,QStringLiteral("错误"),QStringLiteral("临时文件打开错误"));
        return;
    }
    
    ui->btnDownload->setEnabled(false);
    
    //用QNetworkAccessManager发布网络请求,请求下载URL地址表示的文件并创建网络响应
    reply=networkManager.get(QNetworkRequest(newUrl));
    //关联信号与槽
    connect(reply,SIGNAL(finished()),this,SLOT(on_finished()));
    connect(reply,SIGNAL(readyRead()),this,SLOT(on_readyRead()));
    connect(reply,SIGNAL(downloadProgress(qint64,qint64)),
            this,SLOT(on_downloadProgress(qint64,qint64)));
}

第五步

  • 3个自定义槽函数
void MainWindow::on_readyRead()
{
    //读取下载的数据
    downloadedFile->write(reply->readAll());
}
void MainWindow::on_downloadProgress(qint64 bytesRead,qint64 totalBytes)
{
    //设置进度条的值
    ui->progressBar->setMaximum(totalBytes);
    ui->progressBar->setValue(bytesRead);
}
//网络请求结束之后
void MainWindow::on_finished()
{
    QFileInfo fileInfo;
    fileInfo.setFile(downloadedFile->fileName());
    
    //关闭打开的网络文件,然后置空
    downloadedFile->close();
    delete downloadedFile;
    downloadedFile=Q_NULLPTR;
    
    //删除网络响应并置空
    reply->deleteLater();
    reply=Q_NULLPTR;
    
    QMessageBox::information(this,QStringLiteral("提示"),QStringLiteral("下载成功"));

    //如果设置了下载完成后打开,就打开文件
    if(ui->checkOpen->isChecked())
    {
        //调用缺省的应用程序软件打开下载的文件
        QDesktopServices::openUrl(QUrl::fromLocalFile(fileInfo.absoluteFilePath()));
        ui->btnDownload->setEnabled(true);
    }
}

演示效果

Qt:60---网络编程之HTTP通信(QNetworkRequest、QNetworkReply、NetworkAccessManager)_QNetworkReply_02