我的qtcreator学习笔记(三十四)——网络编程之http与ftp(代码片段)

今天也要努力搬砖 今天也要努力搬砖     2022-12-11     471

关键词:

 参考文献:《Qt Creator 快速入门》第三版 霍亚飞编著

网络访问接口

网络请求由QNetworkRequest类来表示,它也作为与请求有关的信息的容器。

QNetworkAccessManager类用来协调网络操作,可以调度创建好的请求,并发射信号来报告进度。此类还可以协调cookies的使用,身份验证请求和代理的使用等。

网络请求的应答使用QNetworkReply类来表示,它会在请求调度完成时由QNetworkAccessManager创建。

1.HTTP

        HTTP(HyperText Transfer Protocol,超文本传输协议)是一个客户端和服务器端直接进行请求和应答的标准。通常由HTTP客户端发起一个请求,建立一个服务器指定端口(默认是80端口)的TCP连接;HTTP服务器在指定的端口监听客户端发送来的请求,一旦收到请求,服务器端就会向客户端发回一个应答。

下面一个示例代码(记得要在.pro文件中添加“QT+=network"),实现http下载文件,其界面布局如下

然后在.h文件中添加以下4个私有成员对象

    QNetworkAccessManager* manager;
    QNetworkReply* reply;
    QUrl url;
    QFile* file;

其中manager使用其get函数发送网络请求,get函数的参数是一个QUrl对象,我们的url成员对象就是用来保存这个对象的。reply监听网络请求的应答。file保存我们下载的文件。

然后添加几个槽函数

    void httpFinished();
    void httpReadyRead();
    void updateDataReadProgress(qint64,qint64);

httpFinished做一些下载完成后的工作。httpReadyRead()函数中将reply内容写入文件file->write(reply->readAll()),updateDataReadProgress函数中更新下载进度条。

再给下载按钮添加click槽函数,槽函数中获取url并调用startRequest函数启动下载,startRequest函数是自定义的成员函数,函数中调用manger->get(QNetworkRequest(url))发送网络请求,然后进行了QNetworkReply对象的几个信号和自定义槽的关联。

最后完整mainwindow.h文件如下

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QUrl>
class QFile;
class QNetworkReply;
class QNetworkAccessManager;

QT_BEGIN_NAMESPACE
namespace Ui  class MainWindow; 
QT_END_NAMESPACE

class MainWindow : public QMainWindow

    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();
    void startRequest(QUrl url);
private slots:
    void httpFinished();
    void httpReadyRead();
    void updateDataReadProgress(qint64,qint64);

    void on_pushButton_clicked();

private:
    Ui::MainWindow *ui;
    QNetworkAccessManager* manager;
    QNetworkReply* reply;
    QUrl url;
    QFile* file;
;
#endif // MAINWINDOW_H

完整 mainwindow.cpp文件如下

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QtNetwork>

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)

    ui->setupUi(this);
    manager=new QNetworkAccessManager(this);
    ui->progressBar->hide();


MainWindow::~MainWindow()

    delete ui;


void MainWindow::startRequest(QUrl url)

    reply=manager->get(QNetworkRequest(url));
    connect(reply,&QNetworkReply::readyRead,this,&MainWindow::httpReadyRead);
    connect(reply,&QNetworkReply::downloadProgress,this,&MainWindow::updateDataReadProgress);
    connect(reply,&QNetworkReply::finished,this,&MainWindow::httpFinished);



void MainWindow::httpFinished()

    ui->progressBar->hide();
    if(file)
    
        file->close();
        delete file;
        file=0;
    
    reply->deleteLater();
    reply=0;


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::on_pushButton_clicked()

    url=ui->lineEdit->text();
    QFileInfo info(url.path());
    QString fileName(info.fileName());
    if(fileName.isEmpty())
        fileName="index.html";
    file=new QFile(fileName);
    if(!file->open(QIODevice::WriteOnly))
    
        delete file;
        file=0;
        return;
    
    startRequest(url);
    ui->progressBar->setValue(0);
    ui->progressBar->show();

2.FTP

FTP(FIle Transfer Protocol,文件传输协议)是一个主要用于浏览远程目录和传输文件的协议。FTP使用两个网络连接,一个用来发送命令,另一个用来输出数据。FTP协议由一个状态,并且需要客户端在传输文件之前发送一些命令。FTP客户端建立一个连接,并在整个会话期间一直保持打开。在每个会话期间可以发生多个传输。

FTP的实现方式与前面的HTTP十分相似,只须在QUrl对象中设置好主机地址、用户名和密码等,然后使用get、put等函数完成文件的获取和上传。

Qt5的兼容性扩展模块QtFtp中包含了支持Qt5的QFtp类。下载地址https://github.com/qt/qtftp

下面一个示例代码实现ftp传输文件(记得要在.pro文件中添加“QT+=network"),需要将与QFtp相关的qftp.cpp、qftp.h、qurlinfo.cpp、qurlinfo.h这4个文件添加到项目中。

其界面布局如下


 

在mainwindow.h文件中添加以下几个私有成员

    QFtp* ftp;
    QHash<QString,bool> isDirectory;
    QString currentPath;
    QFile* file;

 首先是QFtp指针对象,QFtp中提供了多个函数来完成常用的操作命令,分别是connectToHost()函数使用指定的端口号连接到FTP服务器主机,默认端口号是21;login()函数使用指定的用户名和密码登录到FTP服务器;close()函数关闭到ftp服务器的连接;list()函数列出FTP服务器上指定目录的内容,默认列出当前目录的内容;cd()函数改变服务器的工作目录到指定的目录;get()函数从服务器下载指定的文件,put()函数从I/O设备中读取数据,然后写入到服务器上指定的文件;另外还有remove()、mkdir()、rmdir()、rename()等函数。这些命令函数都会返回一个唯一的ID号,可以在后面使用这些ID号来区分不同的命令。

然后是isDirectory用来存储一个路径是否为目录,currentPath存储当前路径,file表示下载的文件。

再添加几个私有槽声明。

    void ftpCommandStarted(int);
    void ftpCommandFinished(int,bool);
    //更新进度
    void updateDataTransferProgress(qint64,qint64);
    //将服务器上的文件添加到TreeWidget部件中
    void addToList(const QUrlInfo &urlInfo);
    //双击一个目录时显示其内容
    void processItem(QTreeWidgetItem*,int);

ftpCommandStarted函数后面会关联到QFtp::commandStarted信号,ftpCommandFinished函数后面会关联到QFtp::commandFinished信号,updateDataTransferProgress函数后面会关联到QFtp::dataTransferProgress信号,addToList函数后面会关联到QFtp::listInfo信号。

再添加连接、返回上一级、下载按钮的click槽函数

    void on_pushButtonConnect_clicked();
    void on_pushButtonGoParent_clicked();
    void on_pushButtonDwonLoad_clicked();

最后总结以下示例代码的主要步骤:1、点击连接按钮时,创建ftp对象,绑定相应函数到ftp的对应信号上,调用ftp->connectToHost函数连接到服务器。调用ftp->login函数登录到服务器。

2、在ftpCommandFinished函数中,登录成功后ftp->list()来显示目录内容(会发送QFtp::listInfo信号,addToList函数绑定到了该信号,addToList中添加item到treeWidget),下载完成后关闭ftp

3、当单击某个item时如果时,目录调用ftp->cd打开该目录,调用ftp->list()显示目录内容;

4、点击download按钮时调用ftp->get()接口下载文件

5、点击返回上一级目录时调用ftp->cd()以及ftp->list()显示上一级目录内容。

完整mainwindow.h内容如下

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QHash>

QT_BEGIN_NAMESPACE
namespace Ui  class MainWindow; 
QT_END_NAMESPACE

class QFtp;
class QFile;
class QUrlInfo;
class QTreeWidgetItem;

class MainWindow : public QMainWindow

    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();
private slots:
    void ftpCommandStarted(int);
    void ftpCommandFinished(int,bool);
    //更新进度
    void updateDataTransferProgress(qint64,qint64);
    //将服务器上的文件添加到TreeWidget部件中
    void addToList(const QUrlInfo &urlInfo);
    //双击一个目录时显示其内容
    void processItem(QTreeWidgetItem*,int);
    void on_pushButtonConnect_clicked();

    void on_pushButtonGoParent_clicked();

    void on_pushButtonDwonLoad_clicked();

private:
    Ui::MainWindow *ui;
    QFtp* ftp;
    QHash<QString,bool> isDirectory;
    QString currentPath;
    QFile* file;
;
#endif // MAINWINDOW_H

完整mainwindow.cpp内容如下

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "qftp.h"
#include <QFile>
#include <QTreeWidgetItem>
#include <QTextCodec>

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)

    ui->setupUi(this);
    ui->progressBar->setValue(0);
    connect(ui->treeWidgetFileList,&QTreeWidget::itemActivated,this,&MainWindow::processItem);


MainWindow::~MainWindow()

    delete ui;


void MainWindow::ftpCommandStarted(int)

    int id=ftp->currentCommand();
    switch(id)
    
    case QFtp::ConnectToHost:
        ui->label->setText(QString::fromLocal8Bit("正在连接到服务器..."));
        break;
    case QFtp::Login:
        ui->label->setText(QString::fromLocal8Bit("正在登陆..."));
        break;
    case QFtp::Get:
        ui->label->setText(QString::fromLocal8Bit("正在下载..."));
        break;
    case QFtp::Close:
        ui->label->setText(QString::fromLocal8Bit("正在关闭连接..."));
        break;
    


void MainWindow::ftpCommandFinished(int, bool error)

    if(ftp->currentCommand()==QFtp::ConnectToHost)
    
            if(error)
                ui->label->setText(QString::fromLocal8Bit("连接服务器出现错误:%1").arg(ftp->errorString()));
            else
                ui->label->setText(QString::fromLocal8Bit("连接到服务器成功"));
    
    else if(ftp->currentCommand()==QFtp::Login)
    
            if(error)
                ui->label->setText(QString::fromLocal8Bit("登录出现错误:%1").arg(ftp->errorString()));
            else
            

                ui->label->setText(QString::fromLocal8Bit("登录成功"));
                ftp->list();
            
    
    else if(ftp->currentCommand()==QFtp::Get)
    
            if(error)
                ui->label->setText(QString::fromLocal8Bit("下载出现错误:%1").arg(ftp->errorString()));
            else
            
                ui->label->setText(QString::fromLocal8Bit("已经完成下载"));
                ftp->close();
            
            ui->pushButtonDwonLoad->setEnabled(true);
    
    else if(ftp->currentCommand()==QFtp::List)
    
            if(isDirectory.isEmpty())
            
                ui->treeWidgetFileList->addTopLevelItem(new QTreeWidgetItem(QStringList()<<tr("<empty>")));
                ui->treeWidgetFileList->setEnabled(false);
                ui->label->setText(QString::fromLocal8Bit("该目录为空"));
            
    
    else if(ftp->currentCommand()==QFtp::Close)
    
            if(error)
                ui->label->setText(QString::fromLocal8Bit("关闭出现错误:%1").arg(ftp->errorString()));
            else
                ui->label->setText(QString::fromLocal8Bit("已经关闭连接"));
    


void MainWindow::updateDataTransferProgress(qint64 readBytes, qint64 totalBytes)

    ui->progressBar->setMaximum(totalBytes);
    ui->progressBar->setValue(readBytes);


void MainWindow::addToList(const QUrlInfo &urlInfo)

    //注意因为服务器上使用UTF-8编码,这里要进行编码转换后再显示中文
    QString name=QString::fromLocal8Bit(urlInfo.name().toLatin1());
    QString owner=QString::fromLocal8Bit(urlInfo.owner().toLatin1());
    QString group=QString::fromLocal8Bit(urlInfo.group().toLatin1());
    QTreeWidgetItem* item=new QTreeWidgetItem;
    item->setText(0,name);
    item->setText(1,QString::number(urlInfo.size()));
    item->setText(2,owner);
    item->setText(3,group);
    item->setText(4,urlInfo.lastModified().toString("yyyy-MM-dd"));
    QPixmap pixmap(urlInfo.isDir()?"../myFtp/dir.png":"../myFtp/file.png");
    item->setIcon(0,pixmap);
    isDirectory[name]=urlInfo.isDir();
    ui->treeWidgetFileList->addTopLevelItem(item);
    if(!ui->treeWidgetFileList->currentItem())
    
        ui->treeWidgetFileList->setCurrentItem(ui->treeWidgetFileList->topLevelItem(0));
        ui->treeWidgetFileList->setEnabled(true);
    




void MainWindow::processItem(QTreeWidgetItem *item, int)

    //如果这个文件是目录则打开
    if(isDirectory[item->text(0)])
    
        //目录名可能是中文,要使用ftp命令cd前需要先进行编码转换
        QString name=QLatin1String(item->text(0).toUtf8());
        ui->treeWidgetFileList->clear();
        isDirectory.clear();
        currentPath+="/"+name;
        ftp->cd(name);
        ftp->list();
        ui->pushButtonGoParent->setEnabled(true);
    


void MainWindow::on_pushButtonConnect_clicked()

    ui->treeWidgetFileList->clear();
    currentPath.clear();
    isDirectory.clear();
    ui->progressBar->setValue(0);

    ftp=new QFtp(this);
    connect(ftp,&QFtp::commandStarted,this,&MainWindow::ftpCommandStarted);
    connect(ftp,&QFtp::commandFinished,this,&MainWindow::ftpCommandFinished);
    connect(ftp,&QFtp::listInfo,this,&MainWindow::addToList);
    connect(ftp,&QFtp::dataTransferProgress,this,&MainWindow::updateDataTransferProgress);

    QString ftpServer=ui->lineEditServer->text();
    QString userName=ui->lineEditUser->text();
    QString passWord=ui->lineEditPwd->text();
    ftp->connectToHost(ftpServer,21);
    ftp->login(userName,passWord);



void MainWindow::on_pushButtonGoParent_clicked()

    ui->treeWidgetFileList->clear();
    isDirectory.clear();
    currentPath=currentPath.left(currentPath.lastIndexOf('/'));
    if(currentPath.isEmpty())
    
        ui->pushButtonGoParent->setEnabled(false);
        ftp->cd("/");
    else
    
        ftp->cd(currentPath);
    
    ftp->list();


void MainWindow::on_pushButtonDwonLoad_clicked()

    QString fileName=ui->treeWidgetFileList->currentItem()->text(0);
    QString name=QLatin1String(fileName.toUtf8());
    file=new QFile(fileName);
    if(!file->open(QIODevice::WriteOnly))
    
        delete file;
        return;
    
    ui->pushButtonDwonLoad->setEnabled(false);
    ftp->get(name,file);

 

 

 

 

 

 

 

 

 

 

 

 

 

 

学习笔记第三十四节课

rsync工具介绍这个是个同步的工具,这个几乎每天都能用到。类似于cp和cp不一样。不同机器传输文件,备份,同台机器,A-B目录传输都可以。假设有一个A目录和一个B目录现在把A拷贝到B下去,A的数据一直在更新,每小时都要拷... 查看详情

学习三十四

11.1LAMP架构介绍11.2MySQL、MariaDB介绍11.3/11.4/11.5MySQL安装扩展mysql5.5源码编译安装http://www.aminglinux.com/bbs/thread-1059-1-1.htmlmysql5.7二进制包安装(变化较大)http://www.apelearn.com/bbs/thread-10105-1-1.htmlLAMP架构介绍工作方式: 查看详情

jmeter学习(三十四)测试报告优化

如果按JMeter默认设置,生成报告如下:从上图可以看出,结果信息比较简单,对于运行成功的case,还可以将就用着。但对于跑失败的case,就只有一行assert错误信息。(信息量太少了,比较难找到失败原因)优化大致过程:1、下... 查看详情

vue2.0学习—计算属性(三十四)(代码片段)

【Vue2.0学习】—计算属性(三十四)定义:要用的属性不存在,要通过已有的属性得来原理:底层借助了Object.defineproperty方法提供的getter和setterget函数什么时候执行?初次读取时会执行当依赖的数据发生变... 查看详情

全国计算机等级考试二级python(2021年9月)备考笔记第十四天(代码片段)

文章目录Python二级等考(第三季)精品题5单项选择题第一题第二题第三题第四题第五题第六题第七题第八题第九题第十题第十一题第十二题第十三题第十四题第十五题第十六题第十七题第十八题第十九题第二十题第二十一题第二十... 查看详情

机器学习面试题

题目一题目二题目三题目四题目五题目六题目七题目八题目九题目十 题目十一题目十二题目十三题目十四题目十五题目十六题目十七题目十八题目十九题目二十题目二十一题目二十二题目二十三题目二十四 题目二十五题... 查看详情

android开发笔记(三十四)excel文件的读写(代码片段)

Android中操作Excel文件的场合较少见,主要是一些专业领域导入导出报表时使用,所以处理Excel读写的开源代码也很稀缺。目前读写Excel主要采用开源库jxl,这个是韩国人写的excel操作工具,虽然最早用在java上,... 查看详情

学习笔记第三十节课

linux网络相关ifconfig查看网卡ip第一章就用过,在sentos6默认就有在7只能使用ipaddr去查看之所以没有是没安装包。ifconfig有一个选项是-a如果终端没有ip的时候是不显示的。ifdown是关闭网卡,ifup是开启网卡。有时候单独针对一个网卡... 查看详情

webpack配置篇(三十四):单元测试和测试覆盖率(代码片段)

说明玩转webpack学习笔记介绍编写单元测试用例技术选型:Mocha+Chai组合测试代码:describe:描述测试文件,it:一个it代表一个测试用例,except:用于断言测试命令:mochaadd.test.js测试用例的例子:add.test.j... 查看详情

我的第三十四篇博客---flask-cookie-sessionsqlchemary

cookie、session 获取cookierequest.get.cookie(‘‘)获取sessionsession.get(‘‘)cookie:指某些网站为了辨别用户身份、进行会话跟踪而储存在用户本地的数据(通常经过加密)复数形式Cookiescookie是由服务器生成,发送给客户端浏览器,浏... 查看详情

我的openwrt开发相关文章

...们能够更加高速的入手。、openwrt学习笔记(三十二): 我的openwrt学习笔记(三十二):openwrt的UCI      2015.9.14open 查看详情

zabbix学习笔记(三十七)

Zabbix学习笔记(三十七)-zabbix自动发现配置方法使用zabbix系统以来在生产中一直没有使用zabbix的自动发现功能,也没有发表过文章,只是在学习中测试了一下,原因很简单,生产中的设备数量比较少,没必要使用自动发现功能... 查看详情

机器学习100天(三十四):034先验概率条件概率

《机器学习100天》完整目录:目录机器学习100天,今天讲的是:先验概率、条件概率。一、先验概率、条件概率机器学习中,我们经常听到两个数学概念:先验概率、后验概率。抛开复杂数学公式不谈,我们通过一个实际的例子... 查看详情

zabbix学习笔记(四十四)

Zabbix学习笔记(四十四)-zabbix系统web页面监控记录时间异常问题解决​今天在巡检zabbix时,发现zabbix的监控记录时间异常,不是本地时间,明显时国际时间,说明是时间的timezone的问题,具体是什么引起的呢?​1、首先我们通... 查看详情

前置操作符和后置操作符(三十四)

        我们之前在C语言中学习了前置++和后置++。应该知道i++是将i的值作为返回值,i+1;++i是先i+1,再返回i的值。那么它们真的有区别吗?我们来编程看看,在VS中进行反汇编,看看汇编代码是怎样... 查看详情

全国计算机等级考试二级python(2021年9月)备考笔记第十二天(代码片段)

文章目录Python二级等考(第三季)精品题3单项选择题第一题第二题第三题第四题第五题第六题第七题第八题第九题第十题第十一题第十二题第十三题第十四题第十五题第十六题第十七题第十八题第十九题第二十题第二十一题第二十... 查看详情

wpf学习第三十四章资源基础(代码片段)

原文:【WPF学习】第三十四章资源基础  WPF允许在代码中以及在标记中的各个位置定义资源(和特定的控件、窗口一起定义,或在整个应用程序中定义)。  资源具有许多重要的优点,如下所述:  高效。可以通过资源定... 查看详情

机器学习sklearn(77):算法实例(三十四)回归线性回归大家族多重共线性:岭回归与lasso岭回归(代码片段)

1最熟悉的陌生人:多重共线性逆矩阵存在的充分必要条件 行列式不为0的充分必要条件              矩阵满秩的充分必要条件           查看详情