前言
上节编程所使用的QUdpSocket、QTcpSocket和QTepServer类都是网络传输层上的类,它们封装实现的是低层的网络进程通信(Socket通信)的功能。
一、Qt网络应用开发
1、Qt网络应用开发则是要在网络传输层基础上进一步实现应用型的协议功能。
应用层的网络协议(如HTTP/FTP/SMTP等)简称“应用协议”,它们运行在TCP/UDP之上,如图下图所示。
Qt 4以前的版本提供QHttp类用于构建HTTP客户端,提供QFtp类用于FTP客户端的开发。
从Qt 5开始,已不再分别提供QHttp类、QFtp 类,应用层的编程使用QNetworkRequest、 QNetworkReply 和
QNetworkAccessManager这几个高层次的类代替,它们提供了更加简单和强大的接口。
2、QNetworkRequest类实现:
网络请求由QNetworkRequest类来表示,作为与请求有关的信息的统一容器,在创建请求对象时指定的URL决定了请求
使用的协议,目前支持HTTP、FTP和本地文件URLs的.上传和下载;
QNetworkAceessManager 类用于协调网络操作,每当一个请求创建后,该类用来调度它,并发射信号来报告进度;而对
于网络请求的应答则使用QNetworkReply类表示,它会在请求被完成调度时由QNetworkAccessManager创建。
二、网络浏览实例(浏览百度搜索引擎)
**(1)、新建Qt Gui应用,名称为“ myHTTP”,类名为“MainWindow”,基类保持"QMainWindow”不变。**完成后先在
“myHTTP.pro”文件中添加语句“QT+= netwotk",并保存该文件。进入设计模式,向界面上拖入一个Text Browser, 然后进
入"mainwindow.h"文件,首先添加类的前置声明:
class QNetworkReply;
class QNetworkAccessManager;
QNetworkAccessManager *manager;
private slots:
void replyFinished(QNetworkReply *);
添加头文件:
#include <QtNetwork>
#include <QUrl>
(2)、在“mainwindow.cpp"文件中,首先添加头文件:
#include <QtNetwork>
然后在构造函数中添加如下代码:
manager = new QNetworkAccessManager(this);
connect(manager,SIGNAL(finished(QNetworkReply*)),this,SLOT(replyFinished(QNetworkReply*)));
manager->get(QNetworkRequest(QUrl("http://www.baidu.com")));
这里首先创建了–个QNetworkAccessManager类的实例,它用来发送网络请求和接收应答。然后关联了管理器的
finished()信号和自定义的槽,每当网络应答结束时都会发射这个信号。最后使用了get()函 数来发送一个网络请求,网
络请求使用QNetworkRequest类表示,get()函 数返回一个QNetworkReply对象。
(3)、下面添加槽的定义:
void MainWindow::replyFinished(QNetworkReply *reply)
{
QString all = reply->readAll();
ui->textBrowser->setText(all);
reply->deleteLater();
}
因为QNetworkReply继承自QIODevice类,所以可以像操作一般的I/O设备一样操作该类。这里使用了readAll()函数来读
取所有的应答数据。在完成数据的读取后,需要使用deleteLater()删除reply对象。
(4)、运行程序,显示出“百度搜索”首页。
三、 文件下载实例
(1)、在网页浏览实例的基础上,实现一般页面文件的下载,并且显示下载进度。
进入设计模式,向界面上拖入Label、Line Edit、Progress Bar和Push Button等部件,
界面设计完成后,效果如下图所示。
(2)、在“mainwindow.h”文件中,添加头文件和类的前置声明:
#include <QUrl>
class QFile;
其次添加如下私有槽声明:
void httpFinished();
void httpReadyRead();
void updateDataReadProgress(qint64,qint64);
void on_pushButton_clicked();
然后再添加一个public函数声明:
void startRequest(QUrl url);
最后添加几个私有对象定义:
QNetworkReply *reply;
QUrl url;
QFile *file;
(3)、在“mainwindow.cpp"文件中,在构造函数中添加:
ui->progressBar->hide();
这里开始将进度条隐藏了,因此在没有下载文件时是不显示进度条的。
(4)、接下来添加几个新函数,首先先添加网络请求函数的实现:
void MainWindow::startRequest(QUrl url)
{
reply = manager->get(QNetworkRequest(url));
connect(reply,SIGNAL(readyRead()),this,SLOT(httpReadyRead()));
connect(reply,SIGNAL(downloadProgress(qint64,qint64)),this,SLOT(updateDataReadProgress(qint64,qint64)));
connect(reply,SIGNAL(finished()),this,SLOT(httpFinished()));
}
这里使用了get()函数发送网络请求,进行了QNetworkReply 对象的几个信号和自定义槽的关联。其中,readyRead()信
号继承自QIODevice类,每当有新的数据可以读取时,都会发射该信号:每当网络请求的下载进度更新时都会发射
downloadProgress()信号,用于更新进度条;每当应答处理结束时,都会发射finished()信号,该信号与前面程序中
QNetworkAccessManager类的finished()信号作用相同,只不过是发送者不同,参数也不同而已。
(5)、下面添加几个槽的定义:
void MainWindow::httpReadyRead()
{
if(file)file->write(reply->readAll());
}
这里首先判断是否创建了文件,如果是,则读取返回的所有数据,然后写入文件中。该文件是在后面的“下载”按钮单击
信号槽中创建并打开的。
void MainWindow::updateDataReadProgress(qint64 bytesRead, qint64 totalBytes)
{
ui->progressBar->setMaximum(totalBytes);
ui->progressBar->setValue(bytesRead);
}
这里设置了进度条的最大值和最小值。
void MainWindow::httpFinished()
{
ui->progressBar->hide();
file->flush();
file->close();
reply->deleteLater();
reply = 0;
delete file;
file = 0;
}
当完成下载后,重新隐藏进度条,删除reply和file 对象。
(6)、进入设计模式,进入“下载”按钮的单击信号的槽,添加如下代码:
void MainWindow::on_pushButton_clicked()
{
url = ui->lineEdit->text();
QFileInfo info(url.path());
QString fileName(info.fileName());
file = new QFile(fileName);
if(!file->open(QIODevice::WriteOnly))
{
qDebug()<<"file open error";
delete file;
file = 0;
return;
}
startRequest(url);
ui->progressBar->setValue(0);
ui->progressBar->show();
}
这里使用要下载的文件名创建了本地文件,使用输入的url 进行网络请求,并显示进度条。
(7)、运行程序,可以输入-一个网络文件地址,单击“下载”按钮将其下载到本地。
例如,下载华军软件园上的软件“Internet Download Manager”。
使用如下URL地址: https://www.onlinedown.net/soft/2729.htm
下载过程中,进度条的动态变化如下图所示:
等待进度条走完后,便下载结束,会在项目的build-myHTTP-Desktop_Qt_5_13_2_MSVC2017_64bit-Debug目录中得到下载的文件。