目录
[1.1 什么是FTP?](#1.1 什么是FTP?)
[1.2 主要特点](#1.2 主要特点)
[1.创建QNetworkAccessManager 实例](#1.创建QNetworkAccessManager 实例)
前言
在工业自动化、数据采集和远程监控系统中,经常需要将本地文件上传到远程服务器。FTP(文件传输协议)作为一种经典的文件传输解决方案,仍然被广泛应用于各种场景。本文将详细介绍如何使用QT框架开发一个功能完善的FTP客户端上位机,实现可靠的文件上传功能。
一、FTP协议简介
1.1 什么是FTP?
FTP(File Transfer Protocol,文件传输协议) 是用于在网络上进行文件传输的一套标准协议,属于TCP/IP协议族中的应用层协议。它于1971年由Abhay Bhushan提出,是最早的互联网协议之一,至今仍在广泛使用。
1.2 主要特点
-
双向传输:支持上传(Upload)和下载(Download)
-
跨平台性:几乎支持所有操作系统
-
可靠性:基于TCP,确保数据传输的可靠性
-
用户管理:支持匿名访问和用户认证
-
目录操作:支持文件列表、目录创建/删除等操作
二、QNetworkAccessManager介绍
QNetworkAccessManager 是 Qt Network 模块的核心类,用于统一管理网络请求(HTTP/FTP/HTTPS/FTPS 等),提供异步、跨平台的网络通信能力。它遵循 "管理器 - 请求 - 回复" 的设计模式,一个 QNetworkAccessManager 实例可处理多个网络请求,无需为每个请求创建新实例,是 Qt 中实现网络通信的首选方案。
1.核心三要素
| 类 | 作用 |
|---|---|
QNetworkAccessManager |
管理器:创建 / 发送请求、管理连接池、分发回复 |
QNetworkRequest |
请求:封装请求地址(URL)、请求头、SSL 配置、超时等参数 |
QNetworkReply |
回复:封装响应数据、状态码、响应头、错误信息,提供数据读取 / 进度监听 |
2.基本工作流程
1. 创建 QNetworkAccessManager 实例(全局唯一即可);
2. 构建 QNetworkRequest,设置 URL、请求头、SSL 等参数;
3. 调用 manager 的方法(get/put/post 等)发送请求,返回 QNetworkReply 实例;
4. 关联 QNetworkReply 的信号(finished/progress/errorOccurred)处理结果;
5. 请求完成后,手动释放 QNetworkReply(deleteLater()),避免内存泄漏。
三、代码实现
1.创建QNetworkAccessManager 实例
全局变量: QNetworkAccessManager *manager;
在构造器中 manager = new QNetworkAccessManager(this);
2.写FTP文件上传函数
cpp
void mainwindow::uploadFtpFile(){
if(fileQueue.isEmpty()){
printInfo(ui->print_textEdit,"上传完成",QColor(0,128,0));
return;
}
currentFile=fileQueue.dequeue();
QFile *file = new QFile("config/"+FtpPath+"/"+currentFile);
if (!file->open(QIODevice::ReadOnly)) {
FtpSuccess=false;
printInfo(ui->print_textEdit,currentFile+"上传失败:找不到参数文件",Qt::red);
delete file;
uploadFtpFile();
return;
}
QUrl url("ftp://"+PlatformIp+"/root/"+currentFile);
if (!FtpUserName.isEmpty() && !FtpPassword.isEmpty()) {
url.setUserName(FtpUserName);
url.setPassword(FtpPassword);
}
QNetworkRequest request(url);
// 开始上传
reply = manager->put(request, file);
file->setParent(reply); // 文件对象由reply管理
connect(reply, &QNetworkReply::finished,
this, &mainwindow::onFinished);
}
void mainwindow::onFinished()
{
if (reply->error() != QNetworkReply::NoError) {
FtpSuccess=false;
printInfo(ui->print_textEdit,currentFile+"上传失败: "+reply->errorString(),Qt::red);
}
reply->deleteLater();
reply->abort();
reply=nullptr;
uploadFtpFile();
}
3.在点击事件中调用FTP上传函数
cpp
void mainwindow::on_pushButton_clicked()
{
//判断网络有没有连接上
if(net_flag==0){
QMessageBox::information(this,"提示","请先连接平台后再上传参数");
return;
}
int replays;
replays=QMessageBox::question(this,"确认","您确定需要上传参数吗?",QMessageBox::Yes,QMessageBox::No);
if(replays==QMessageBox::No){
return;
}
if(!fileQueue.isEmpty()){
QMessageBox::information(this,"提示","当前正在上传参数,请稍候");
return;
}
for(int i=0;i<FtpFileList.size();i++){
fileQueue.enqueue(FtpFileList.at(i));
}
printInfo(ui->print_textEdit,"正在上传参数文件...",Qt::black);
FtpSuccess=true;
uploadFtpFile();
}
FTP上传多文件整体思路就是将要上传的文件名放到一个字符串的队列中,发送完成一个就在队列里面再取一个文件,直到队列里面为空以后,就判断发送完成了,注意发送完了要清一下reply。
reply->deleteLater();
reply->abort();
reply=nullptr;
本地的文件路径是 QFile *file = new QFile("config/test.txt");
上传后的文件路径是 QUrl url("ftp://"192.168.0.22"/root/test.txt");
根据自己需要上传的文件名拼接即可。
字符串队列使用的时候需要调用 #include <QQueue>库,
然后初始化 QQueue<QString> fileQueue。
使用的时候,currentFile=fileQueue.dequeue();即可从队列中拿出第一个字符串并从队列中清除。
fileQueue.enqueue(FtpFileList.at(i));可以给队列增加一个字符串元素。
总结
QT实现FTP的文件上传还是比较简单的,主要是把逻辑理清就可以了,还有一个问题就是如果FTP服务器连接不上的话,会一直请求上传,不会到完成的槽函数中,也不会到报错的槽函数中,因为我是先用TCP连接的服务器再用FTP上传文件,我这里没有做超时处理,QT5.15及以上可以用manager->setTransferTimeout(5000);设置超时,QT5.15以下需要自己写一个超时的倒计时函数,这里就不再详细写了。
