QT:tftp client 和 Server

1.TFTP简介

TFTP(Trivial File Transfer Protocol,简单文件传输协议)是TCP/IP协议族中的一个用来在客户机与服务器之间进行简单文件传输的协议,提供不复杂、开销不大的文件传输服务。端口号为69。

FTP是一个传输文件的简单协议,它基于UDP协议而实现,但是我们也不能确定有些TFTP协议是基于其它传输协议完成的。此协议设计的时候是进行小文件传输的。因此它不具备通常的FTP的许多功能,它只能从文件服务器上获得或写入文件,不能列出目录,不进行认证,它传输8位数据。传输中有三种模式:netascii,这是8位的ASCII码形式,另一种是octet,这是8位源数据类型;最后一种mail已经不再支持,它将返回的数据直接返回给用户而不是保存为文件。

参考链接:https://blog.csdn.net/weixin_43996145/article/details/134265843?spm=1001.2014.3001.5501

2.TFTP Client

2.1 界面

在这里插入图片描述

2.2 源码

uint32_t ClientSocket::write(const char* data, size_t size)
{return socket_->write(data, size);
}TFtpClient::TFtpClient(QObject *parent): QObject(parent), socket(new QUdpSocket(this))
{connect(socket, &QUdpSocket::readyRead,this, &TFtpClient::readPendingDatagrams);connect(socket, &QUdpSocket::connected,this, &TFtpClient::connected);connect(socket, SIGNAL(error(QAbstractSocket::SocketError)),this, SLOT(connectError(QAbstractSocket::SocketError)));
}void TFtpClient::setHostPort(QString const& host, quint16 port)
{host_ = host;port_ = port;
}void TFtpClient::getFile(QString const& localFileName, QString const& remoteFileName)
{isPut_ = false;localFileName_ = localFileName;remoteFileName_ = remoteFileName;socket->connectToHost(host_, port_);
}void TFtpClient::putFile(QString const& localFileName, QString const& remoteFileName)
{isPut_ = true;localFileName_ = localFileName;remoteFileName_ = remoteFileName;socket->connectToHost(host_, port_);
}void TFtpClient::stopFileTransfer()
{socket->disconnectFromHost();
}void TFtpClient::connected()
{ClientSocket* udp = new ClientSocket(socket);tftpFile_ = TFtpClientFile::Ptr(new TFtpClientFile(udp));bool isOK = true;if(isPut_)isOK = tftpFile_->putFile(localFileName_.toStdString(),remoteFileName_.toStdString(), TFtp::BINARY);elseisOK = tftpFile_->getFile(localFileName_.toStdString(),remoteFileName_.toStdString(), TFtp::BINARY);if(!isOK)emit error("Local File not Found");elseemit started();
}void TFtpClient::connectError(QAbstractSocket::SocketError)
{emit error("Connect host is failed");
}void TFtpClient::readPendingDatagrams()
{while (socket->hasPendingDatagrams()) {QNetworkDatagram datagram = socket->receiveDatagram();QByteArray d = datagram.data();if(tftpFile_){tftpFile_->process((uint8_t *)d.data(), d.size());emit progress(tftpFile_->file_bytes(), tftpFile_->filesize());if(tftpFile_->is_finished()){if(tftpFile_->is_error())emit error(QString::fromStdString(tftpFile_->error_msg()));elseemit finished();}}}
}TFtpClientWidget::TFtpClientWidget(QWidget *parent): QWidget(parent), ui(new Ui::TFtpClientWidget), tftpClient(new TFtpClient(this))
{ui->setupUi(this);connect(ui->btnBrowse, SIGNAL(clicked()), this, SLOT(onSelectLocalFile()));connect(ui->btnGet, SIGNAL(clicked()), this, SLOT(onGetFile()));connect(ui->btnPut, SIGNAL(clicked()), this, SLOT(onPutFile()));connect(ui->btnBreak, SIGNAL(clicked()), this, SLOT(onStop()));connect(tftpClient, &TFtpClient::started, this, &TFtpClientWidget::onStarted);connect(tftpClient, &TFtpClient::progress, this, &TFtpClientWidget::onProgress);connect(tftpClient, &TFtpClient::finished, this, &TFtpClientWidget::onFinished);connect(tftpClient, &TFtpClient::error, this, &TFtpClientWidget::onError);
}TFtpClientWidget::~TFtpClientWidget()
{delete ui;
}void TFtpClientWidget::onGetFile()
{tftpClient->stopFileTransfer();tftpClient->setHostPort(ui->lineEditHost->text(), ui->spinBoxPort->value());tftpClient->getFile(ui->lineEditLocalFile->text(), ui->lineEditRemoteFile->text());ui->progressBar->setValue(0);
}void TFtpClientWidget::onPutFile()
{tftpClient->stopFileTransfer();tftpClient->setHostPort(ui->lineEditHost->text(), ui->spinBoxPort->value());tftpClient->putFile(ui->lineEditLocalFile->text(), ui->lineEditRemoteFile->text());ui->progressBar->setValue(0);
}void TFtpClientWidget::onStarted()
{enableButtons(false);
}void TFtpClientWidget::onProgress(quint64 bytes, quint64 total)
{if(total > 0)ui->progressBar->setValue(bytes * 100 / total);else{int value = ui->progressBar->value();ui->progressBar->setValue(QRandomGenerator(value).bounded(value, 99));}
}void TFtpClientWidget::onStop()
{enableButtons(true);tftpClient->stopFileTransfer();
}void TFtpClientWidget::onFinished()
{if(tftpClient->isPut())QMessageBox::information(this, "TFtpClient", "Put is done!");elseQMessageBox::information(this, "TFtpClient", "Get is done!");enableButtons(true);
}void TFtpClientWidget::onError(QString const& error)
{QMessageBox::critical(this, "TFtpClient", error);enableButtons(true);
}void TFtpClientWidget::onSelectLocalFile()
{static QString filePath;QFileDialog dialog(this, tr("Select File"), filePath, tr("All files (*.*)"));if(dialog.exec() == QDialog::Rejected)return;QStringList fileNames = dialog.selectedFiles();if(fileNames.isEmpty())return;QString fileName = fileNames.first();filePath = QFileInfo(fileName).filePath();ui->lineEditLocalFile->setText(fileName);
}void TFtpClientWidget::enableButtons(bool enable)
{ui->btnGet->setEnabled(enable);ui->btnPut->setEnabled(enable);ui->btnBreak->setDisabled(enable);
}

3.TFTP Server

3.1 界面

在这里插入图片描述

3.2 源码

uint32_t ServerSocket::write(const char* data, size_t size)
{return socket_->writeDatagram(data, size, host_, port_);
}TFtpServer::TFtpServer(QObject *parent): QObject(parent), socket(new QUdpSocket(this)), fileManager_(new TFtpFileManager())
{connect(socket, &QUdpSocket::readyRead,this, &TFtpServer::readPendingDatagrams);
}void TFtpServer::setFilePath(QString const& filePath)
{if(!filePath.endsWith("/"))filePath_ = filePath + "/";
}void TFtpServer::start()
{if(!socket->bind(TFTP_PORT))emit bindError();
}void TFtpServer::stop()
{socket->close();
}void TFtpServer::readPendingDatagrams()
{while (socket->hasPendingDatagrams()) {QNetworkDatagram datagram = socket->receiveDatagram();QByteArray d = datagram.data();QString  transferId = QString("%1:%2").arg(datagram.senderAddress().toString()).arg(datagram.senderPort());TFtpServerFile::Ptr file = fileManager_->find(transferId.toStdString());if(file)file->process((uint8_t *)d.data(), d.size());else{ServerSocket* udp = new ServerSocket(socket, datagram.senderAddress(), datagram.senderPort());file = TFtpServerFile::Ptr(new TFtpServerFile(udp, filePath_.toStdString(), transferId.toStdString()));fileManager_->add(file);file->process((uint8_t *)d.data(), d.size());emit startFile(transferId, QString::fromStdString(file->filename()));}if(!file->is_finished()){if(file->type() == TFtpServerFile::Read)emit statusText(QString("Downloding file: %1, progress: %4% blockNumber(%2/%3)").arg(QString::fromStdString(file->filename())).arg(file->block_number()).arg(file->block_numbers()).arg(file->block_number() * 100 / file->block_numbers()));elseemit statusText(QString("Uploading file: %1, blockNumber(%2)").arg(QString::fromStdString(file->filename())).arg(file->block_number()));emit progress(transferId, file->file_bytes(), file->filesize());}else{if(file->is_error())emit statusText(QString("%1:%2").arg((int)file->error()).arg(QString::fromStdString(file->error_msg())));elseemit statusText(QString());emit progress(transferId, file->file_bytes(), file->filesize());emit stopFile(transferId);fileManager_->remove(file->transfer_id());}}
}TFtpServerWidget::TFtpServerWidget(QWidget *parent): QWidget(parent), ui(new Ui::TFtpServerWidget), tftpServer(new TFtpServer(this))
{ui->setupUi(this);loadSettings();connect(ui->btnBrowse, SIGNAL(clicked()), this, SLOT(selectTFtpDir()));connect(ui->currentDir, SIGNAL(currentIndexChanged(QString)), this, SLOT(setCurrentDir(QString)));connect(tftpServer, SIGNAL(startFile(QString,QString)), this, SLOT(onStartFile(QString,QString)));connect(tftpServer, SIGNAL(progress(QString,quint64,quint64)), this, SLOT(onProgress(QString,quint64,quint64)));connect(tftpServer, SIGNAL(stopFile(QString)), this, SLOT(onStopFile(QString)));connect(tftpServer, SIGNAL(bindError()), this, SLOT(onBindError()));tftpServer->start();
}TFtpServerWidget::~TFtpServerWidget()
{saveSettinggs();tftpServer->stop();delete ui;
}void TFtpServerWidget::selectTFtpDir()
{QString filePath = QFileDialog::getExistingDirectory(this,"Select Dir", ui->currentDir->currentText());if(filePath.isEmpty())return;int index  = ui->currentDir->findText(filePath);if(index != -1)ui->currentDir->setCurrentIndex(index);else{if(ui->currentDir->count() >= MAX_PATH_SIZE)ui->currentDir->removeItem(0);ui->currentDir->addItem(filePath);ui->currentDir->setCurrentIndex(ui->currentDir->count()  - 1);}
}void TFtpServerWidget::setCurrentDir(QString const& path)
{tftpServer->setFilePath(path);
}void TFtpServerWidget::onStartFile(QString const&transferId, QString const& fileName)
{ui->clientTables->addTopLevelItem(new QTreeWidgetItem(QStringList()<< transferId << fileName << QTime::currentTime().toString("hh:mm:ss")));
}void TFtpServerWidget::onProgress(QString const&transferId, quint64 bytes, quint64 total)
{QList<QTreeWidgetItem*> items = ui->clientTables->findItems(transferId, Qt::MatchCaseSensitive);for(int i = 0; i < items.size(); i++){if(total == 0)items[i]->setText(5, QString::number(bytes));else{   items[i]->setText(3, QString("%1%").arg(bytes * 100 / total));items[i]->setText(5, QString::number(total));}items[i]->setText(4, QString::number(bytes));}
}void TFtpServerWidget::onStopFile(QString const&transferId)
{QList<QTreeWidgetItem*> items = ui->clientTables->findItems(transferId, Qt::MatchCaseSensitive);for(int i = 0; i < items.size(); i++){int index = ui->clientTables->indexOfTopLevelItem(items[i]);ui->clientTables->takeTopLevelItem(index);}
}void TFtpServerWidget::saveSettinggs()
{QSettings settings(QCoreApplication::applicationName(), QCoreApplication::applicationVersion());QStringList dirs;for(int i = 0; i < ui->currentDir->count(); i++)dirs << ui->currentDir->itemText(i);settings.setValue("dirs", dirs);settings.setValue("currentDir", ui->currentDir->currentText());
}void TFtpServerWidget::loadSettings()
{QSettings settings(QCoreApplication::applicationName(), QCoreApplication::applicationVersion());QStringList dirs = settings.value("dirs", QStringList()).toStringList();QString currentDir = settings.value("currentDir", QString()).toString();ui->currentDir->addItems(dirs);int index  = ui->currentDir->findText(currentDir);if(index != -1){tftpServer->setFilePath(currentDir);ui->currentDir->setCurrentIndex(index);}else{tftpServer->setFilePath(QApplication::applicationDirPath());ui->currentDir->addItem(QApplication::applicationDirPath());}
}void TFtpServerWidget::onBindError()
{QMessageBox::critical(this, "TFtpServer", "Port(69) is already occupied!");ui->btnBrowse->setDisabled(true);ui->currentDir->setDisabled(true);setWindowTitle("TFtpServer is not running");
}

4.工程链接

源码工程链接:https://download.csdn.net/download/weixin_43996145/90300559

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/66782.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

WPF5-x名称空间

1. x名称空间2. x名称空间内容3. x名称空间内容分类 3.1. x:Name3.2. x:Key3.3. x:Class3.4. x:TypeArguments 4. 总结 1. x名称空间 “x名称空间”的x是映射XAML名称空间时给它取的名字&#xff08;取XAML的首字母&#xff09;&#xff0c;里面的成员&#xff08;如x:Class、…

前端jquery 实现文本框输入出现自动补全提示功能

git仓库&#xff1a;web_study/some-demos/inputAutoFit at main Cong0925/web_study (github.com) 压缩包&#xff1a;已绑定到指定资源 示例图&#xff1a; 实现说明: 1.首先&#xff0c;html部分设置好相关的定位标签如图&#xff1a; 2.主要函数 3.默认数据

缓存之美:万文详解 Caffeine 实现原理(上)

由于社区最大字数限制&#xff0c;本文章将分为两篇&#xff0c;第二篇文章为缓存之美&#xff1a;万文详解 Caffeine 实现原理&#xff08;下&#xff09; 大家好&#xff0c;我是 方圆。文章将采用“总-分-总”的结构对配置固定大小元素驱逐策略的 Caffeine 缓存进行介绍&…

Qt实践:一个简单的丝滑侧滑栏实现

Qt实践&#xff1a;一个简单的丝滑侧滑栏实现 笔者前段时间突然看到了侧滑栏&#xff0c;觉得这个抽屉式的侧滑栏非常的有趣&#xff0c;打算这里首先尝试实现一个简单的丝滑侧滑栏。 首先是上效果图 &#xff08;C&#xff0c;GIF帧率砍到毛都不剩了&#xff09; QProperty…

工作流引擎Camunda与LiteFlow核心组件对比

以下为 Camunda 7 和 LiteFlow 详细的介绍&#xff0c;包括它们的核心组件和用途。 1. Camunda 7 详细介绍 Camunda 7 是一个基于 BPMN 2.0 标准的企业级工作流和决策自动化平台。它被广泛应用于复杂业务流程的管理和执行&#xff0c;其核心目标是通过流程自动化来提升企业效…

css动画水球图

由于echarts水球图动画会导致ios卡顿&#xff0c;所以纯css模拟 展示效果 组件 <template><div class"water-box"><div class"water"><div class"progress" :style"{ --newProgress: newProgress % }"><…

iOS 权限管理:同时请求相机和麦克风权限的最佳实践

引言 在开发视频类应用时&#xff0c;我们常常会遇到需要同时请求相机和麦克风权限的场景。比如&#xff0c;在用户发布视频动态时&#xff0c;相机用于捕捉画面&#xff0c;麦克风用于录制声音&#xff1b;又或者在直播功能中&#xff0c;只有获得这两项权限&#xff0c;用户…

Java 泛型上下限详解:以 Info 泛型类和方法实现为例

本文将通过一个实际示例&#xff0c;来深入讲解 Java 泛型中的上下限及其应用场景。在这个示例中&#xff0c;我们会实现一个泛型类 Info 和两个泛型方法 upperLimit 和 lowerLimit&#xff0c;并解释其工作机制。 1. 什么是 Java 泛型上下限&#xff1f; Java 泛型的上下限是…

客户服务创新:数字化时代的策略与实践

在数字化时代背景下&#xff0c;客户服务已成为企业竞争的关键领域。随着消费者需求的日益多样化和个性化&#xff0c;传统的客户服务模式已难以满足市场的要求。因此&#xff0c;企业需要不断探索和创新客户服务策略&#xff0c;以适应数字化时代的变化。 一、数字化时代客户服…

【PyCharm】远程连接Linux服务器

【PyCharm】相关链接 【PyCharm】连接Jupyter Notebook【PyCharm】快捷键使用【PyCharm】远程连接Linux服务器【PyCharm】设置为中文界面 【PyCharm】远程连接Linux服务器 PyCharm 提供了远程开发的功能&#xff0c;使得开发者可以在本地编辑代码或使用服务器资源。 下面将详…

十三、数据的的输入与输出(3)

数据的输出 writeClipboard&#xff08;&#xff09;函数 writeClipboard&#xff08;&#xff09;函数可以将数据输出至剪贴板。 例如&#xff0c;将R的内置数据集iris输出到剪贴板&#xff0c;在进入Excel中点击"粘贴"。 head(iris) #查看数据集Sepal.L…

PyQt5之QDialog

1.描述 QDialog是对话窗口的基类&#xff0c;对话窗口是顶级窗口&#xff0c;主要用于短期任务和与用户的简短通信。 可分为模态对话框和非模态对话框。 模态对话框又可以分为应用程序级别和窗口级别。 ​ 应用程序级别&#xff1a;当该种模态的对话框出现时&#xff0c;用…

Next.js:构建大模型智能体GPT研究者应用的 Web开发框架

Next.js&#xff1a;构建大模型智能体GPT研究者应用的 Web开发框架 Next.js 基础知识 Next.js 是由 Vercel 公司开发维护的框架&#xff0c;极大地简化了 React 应用的开发流程。其核心特性包括&#xff1a; 服务器端渲染&#xff08;SSR&#xff09;与静态站点生成&#xff…

车载软件架构 --- CP和AP作为中央计算平台的软件架构双核心

我是穿拖鞋的汉子&#xff0c;魔都中坚持长期主义的汽车电子工程师。 老规矩&#xff0c;分享一段喜欢的文字&#xff0c;避免自己成为高知识低文化的工程师&#xff1a; 简单&#xff0c;单纯&#xff0c;喜欢独处&#xff0c;独来独往&#xff0c;不易合同频过着接地气的生活…

华为EC6110T-海思Hi3798MV310_安卓9.0_通刷-强刷固件包

华为EC6110T-海思Hi3798MV310_安卓9.0_通刷-强刷固件包 刷机教程说明&#xff1a; 适用机型&#xff1a;华为EC6110-T、华为EC6110-U、华为EC6110-M 破解总分为两个部分&#xff1a;拆机短接破解&#xff08;保留IPTV&#xff09;和OTT卡刷&#xff08;不保留IPTV&#xff09…

Element使用表单重置如果不使用prop,重置无法生效

文章目录 为什么需要 prop&#xff1f;示例&#xff1a;使用 prop 的正确方式关键点总结 在 element-ui 的 el-form 组件中&#xff0c; prop 属性是与表单验证和表单字段绑定密切相关的&#xff0c;尤其在使用 resetFields() 重置表单数据时。 如果不使用 prop&#xff0…

使用pyboard、micropython和tja1050进行can通信

单片机和can收发器之间tx、rx不需要交叉接线&#xff01;&#xff01;&#xff01; tja1050的rx接Y3、tx接Y4 from pyb import CANcan CAN(1) can.init(modecan.NORMAL, prescaler6, sjw1, bs14, bs22, auto_restartTrue) # 1Mbps的配置&#xff0c;本文使用的micropython1.…

【信息系统项目管理师】高分论文:论信息系统项目的干系人管理(社保信息管理系统)

更多内容请见: 备考信息系统项目管理师-专栏介绍和目录 文章目录 论文1、识别干系人2、规划干系人参与3、管理干系人4、监督干系人论文 2016年3月,我作为项目经理参与了XX市社保信息管理系统项目的建设,该项目投资共450万元人民币,建设工期为1年,通过该项目的实施,在XX市…

JavaScript系列(39)-- Web Workers技术详解

JavaScript Web Workers技术详解 &#x1f504; 今天&#xff0c;让我们深入了解Web Workers技术&#xff0c;这是一种能够在后台线程中运行脚本的强大特性&#xff0c;可以避免阻塞主线程&#xff0c;提升Web应用的性能和响应性。 Web Workers基础概念 &#x1f31f; &#…

26、正则表达式

目录 一. 匹配字符 .&#xff1a;匹配除换行符外的任意单个字符。 二. 位置锚点 ^&#xff1a;匹配输入字符串的开始位置。 $&#xff1a;匹配输入字符串的结束位置。 \b&#xff1a;匹配单词边界。 \B&#xff1a;匹配非单词边界。 三. 重复限定符 *&#xff1a;匹配…