Qt实现TFTP Server和 TFTP Client(四)

3.3 Server

Server包括下面3个类:

  • ServerSocket
  • TFtpServer
  • TFtpServerWidget
3.3.1 ServerSocket

ServerSocket从BaseUdp派生实现write接口.

3.3.1.1 ServerSocket定义
class QUdpSocket;
class ServerSocket : public BaseUdp
{
public:ServerSocket(QUdpSocket* socket, QHostAddress const& host,uint16_t port): socket_(socket), host_(host), port_(port){}uint32_t write(const char* data, size_t size) override;
private:QUdpSocket* socket_;QHostAddress host_;uint16_t port_;
};

成员函数说明:

  • write 重载函数,实现父类BaseUdp中定义的write接口。
3.3.1.2 ServerSocket实现
uint32_t ServerSocket::write(const char* data, size_t size)
{return socket_->writeDatagram(data, size, host_, port_);
}

函数实现说明:

  • 直接调用QUdpSocket对象的writeDatagram接口。
3.3.2 TFtpServer

TFtpServer类通过TFtpServerFile类实现一个TFTP服务端,接受上下载文件请求。

3.3.2.1 TFtpServer定义
class QUdpSocket;
class TFtpServer:  public QObject
{
Q_OBJECT
public:TFtpServer(QObject *parent = nullptr);void setFilePath(QString const& filePath);void start();void stop();
signals:void bindError();void startFile(QString const&transferId, QString const& fileName);void progress(QString const&transferId, quint64 bytes, quint64 total);void statusText(QString const& text);void stopFile(QString const&transferId);private slots:void readPendingDatagrams();
private:private:QUdpSocket* socket;QString filePath_;TFtpFileManager::Ptr fileManager_;const uint16_t TFTP_PORT = 69;
};

成员函数说明:

  • setFilePath 配置TFTP服务器的下载文件路径.
  • start 启动TFTP服务.
  • stop 停止TFTP服务.

信号说明:

  • bindError 绑定UDP端口错误信号
  • startFile 文件开始传输信号
  • progress 文件传输进度信号
  • statusText 状态文本变化信号
  • stopFile 停止文件传输信号
    槽函数说明:
  • readPendingDatagrams 从TFTP客户端读数据处理函数
3.3.2.1 TFtpServer实现
  • 构造函数
TFtpServer::TFtpServer(QObject *parent): QObject(parent), socket(new QUdpSocket(this)), fileManager_(new TFtpFileManager())
{connect(socket, &QUdpSocket::readyRead,this, &TFtpServer::readPendingDatagrams);
}

函数说明:

  • 创建QUdpSocket对象socket

  • 连接socket的信号和对应槽函数。

  • setFilePath/start/stop/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());}}
}

函数说明:

  • setFilePath 保存文件路径地址
  • start 绑定TFTP端口,启动服务,绑定失败发送bindError信号。
  • stop 关闭socket,停止服务
  • readPendingDatagrams 从socket读取数据包,构造transferId,根据transferId判断是新连接还是旧连接,旧连接则找到对应TFtpServerFile对象处理文件上下载;新连接则TFtpServerFile对象处理文件上下载,并保存TFtpServerFile对象;处理数据完毕后,根据结束与否进行相应的处理。
3.3.3 TFtpServerWidget

TFtpServerWidget从QWidget派生一个窗口类,负责设置下载文件路径,并显示文件传输进度等界面操作。

3.3.3.1 TFtpServerWidget定义
class TFtpServer;
class TFtpServerWidget : public QWidget
{Q_OBJECTpublic:TFtpServerWidget(QWidget *parent = nullptr);~TFtpServerWidget();private slots:void selectTFtpDir();void setCurrentDir(QString const& path);void onBindError();void onStartFile(QString const&transferId, QString const& fileName);void onProgress(QString const&transferId, quint64 bytes, quint64 total);void onStopFile(QString const&transferId);
private:void saveSettinggs();void loadSettings();
private:Ui::TFtpServerWidget *ui;TFtpServer* tftpServer;int MAX_PATH_SIZE = 5;};
3.3.3.2 TFtpServerWidget实现
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");
}

Qt实现TFTP Server和 TFTP Client(三)

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

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

相关文章

Java 学习和实践笔记(49):用javabean和一维数组的方式来存储表格数据

还是存储下面这个表格的数据&#xff0c;但使用另一种方法来做。 用javabean和一维数组的方法来做&#xff0c;示例代码如下&#xff1a; /*先创建一个类&#xff0c;其实就是创建好一个只有各属性列的空表格*/ class Employees {private int id;private String name;private …

[2021]Zookeeper getAcl命令未授权访问漏洞概述与解决

今天在漏洞扫描的时候蹦出来一个zookeeper的漏洞问题&#xff0c;即使是非zookeeper的节点&#xff0c;或者是非集群内部节点&#xff0c;也可以通过nc扫描2181端口&#xff0c;获取极多的zk信息。关于漏洞的详细描述参考apache zookeeper官方概述&#xff1a;CVE-2018-8012: A…

Self-Consistency Improves Chain of Thought Reasoning in Language Models阅读笔记

论文链接&#xff1a;https://arxiv.org/pdf/2203.11171.pdf 又到了读论文的时间&#xff0c;内心有点疲惫。这几天还是在看CoT的文章&#xff0c;今天这篇是讲如何利用self-consistency&#xff08;自我一致性&#xff09;来改进大语言模型的思维链推理过程。什么是self-cons…

5.4 物联网RK3399项目开发实录-Android开发之编译 Android10.0 固件(wulianjishu666)

物联网项目开发实例&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/11VQMhHfIL9mZhNlls4wmjw?pwd0gfa 4. 编译 Android10.0 固件 4.1. 下载 Android SDK 由于 SDK 较大&#xff0c;可以去下载页面选择云盘下载 Firefly-RK3399_Android10.0_git_20211222.7z&#x…

Android-Handler详解_原理解析

为了方便阅读将文章分为使用篇和源码解析两篇&#xff0c;上一篇已经写了Handler是什么、有什么、怎们用&#xff0c;这一片从源码的角度分析完整流程&#xff0c;看看Handler消息机制到底是啥原理。才疏学浅&#xff0c;如有错误&#xff0c;欢迎指正&#xff0c;多谢。 完整…

标定系列——预备知识-OpenCV中实现Rodrigues变换的函数(二)

标定系列——预备知识-OpenCV中实现Rodrigues变换的函数&#xff08;二&#xff09; 说明记录 说明 简单介绍罗德里格斯变换以及OpenCV中的实现函数 记录

ClickHouse10-ClickHouse中Kafka表引擎

Kafka表引擎也是一种常见的表引擎&#xff0c;在很多大数据量的场景下&#xff0c;会从源通过Kafka将数据输送到ClickHouse&#xff0c;Kafka作为输送的方式&#xff0c;ClickHouse作为存储引擎与查询引擎&#xff0c;大数据量的数据可以得到快速的、高压缩的存储。 Kafka大家…

Ubuntu 配置 kubernetes 学习环境,让外部访问 dashboard

Ubuntu 配置 kubernetes 学习环境 一、安装 1. minikube 首先下载一下 minikube&#xff0c;这是一个单机版的 k8s&#xff0c;只需要有容器环境就可以轻松启动和学习 k8s。 首先你需要有Docker、QEMU、Hyperkit等其中之一的容器环境&#xff0c;以下使用 docker 进行。 对…

【C++】编码规范之可靠性原则

C编码规范中的可靠性原则是确保代码的可读性、可维护性和稳定性&#xff0c;以下是几个小点及其例子&#xff1a; 避免使用全局变量&#xff1a; 如果需要多个变量在全局范围内使用&#xff0c;可用context&#xff08;结构体/类&#xff09;解决耦合性问题 // 不推荐的写法&…

65W智能快充—同为科技桌面PDU插座推荐

近10年&#xff0c;移动设备的智能化、功能化已经完全且紧密的融入到我们的基础生活与工作当中。 在常态化的电子设备的应用中&#xff0c;设备的电力续航以及后续的供电充电就尤为重要。 就目前而言&#xff0c;所有消费电子产品中的输入以及充电的接口&#xff0c;usb-c可以…

酷开科技依托酷开系统用“平台+产品+场景”塑造全屋智能生活!

杰弗里摩尔的“鸿沟理论”中写道&#xff1a;高科技企业推进产品的早期市场和产品被广泛接受的主流市场之间&#xff0c;存在着一条巨大的“鸿沟”。“鸿沟”&#xff0c;指产品吸引早期接纳者后、赢得更多客户前的那段间歇&#xff0c;以及其中可预知和不可预知的阻碍。多数产…

面试中会被问到的GIT问题解答(含答案)

在现代软件开发中&#xff0c;Git已经成为了版本控制系统的事实标准。无论是在个人项目还是大型企业级开发中&#xff0c;Git都是不可或缺的工具。因此&#xff0c;掌握Git的基本操作和高级特性对于软件开发者来说是非常重要的。以下是根据提供的文件内容&#xff0c;总结出的3…

基于Rflysim平台的无人机拦截三维比例导引算法仿真

【后厂村路钢铁侠出品】 一、Rflysim简介 RflySim是一套专为科研和教育打造的Pixhawk /PX4 和MATLAB/Simulink生态系统或工具链&#xff0c;采用基于模型设计&#xff08;Model-Based Design&#xff0c; MBD&#xff09;的思想&#xff0c;可用于无人系统的控制和安全测试。…

如何创建azure pipeline

Azure Pipelines是一种持续集成和持续交付&#xff08;CI/CD&#xff09;工具&#xff0c;可以帮助开发团队自动化构建、测试和部署应用程序。以下是创建Azure Pipeline的步骤&#xff1a; 登录到Azure DevOps&#xff08;https://dev.azure.com/&#xff09;。在Azure DevOps…

区块链食品溯源案例实现(一)

引言&#xff1a; 食品安全问题一直是社会关注的热点&#xff0c;而食品溯源作为解决食品安全问题的重要手段&#xff0c;其重要性不言而喻。传统的食品溯源系统往往存在数据易被篡改、信息不透明等问题&#xff0c;而区块链技术的引入&#xff0c;为食品溯源带来了革命性的变革…

设计模式之装饰模式解析

装饰模式 1&#xff09;概述 1.定义 动态地给一个对象增加一些额外的职责&#xff0c;在增加对象功能时&#xff0c;装饰模式比生成子类实现更为灵活。 2.作用 装饰模式可以在不改变一个对象本身功能的基础上给对象增加额外的新行为。 3.结构图 4.角色 Component&#xf…

【React】React 内置 Hook

React 内置 Hook 是一组允许你在函数组件中使用 state 和其他 React 特性的函数。它们极大地扩展了函数组件的功能,使得在无需编写 class 的情况下也能使用 React 的全部功能。以下是一些主要的 React 内置 Hook 的介绍: 1.useState useState 是用于在函数组件中添加状态(…

深入理解 @Transactional 注解在 Spring 中的应用

前言&#xff1a;在 Java 开发中&#xff0c;事务管理是非常重要的一环。Spring 框架提供了Transactional注解来简化事务管理的操作&#xff0c;本文将深入介绍Transactional注解的用法&#xff0c;并结合代码示例进行详细讨论。 1.Transactional 注解简介 Transactional注解是…

银行卡的分类

银行卡是银行账户的一种体现形式&#xff0c;它是由银行机构发行的具有消费信用、转账结算、存取现金等全部或部分功能作为结算支付工具的各类卡的统称。 &#xff08;1&#xff09;按是否具有授信额度分类 ①借记卡&#xff1a;借记卡是指发卡银行向申请人签发的&#xff0c;没…

Machine Learning机器学习之向量机(Support Vector Machine,SVM)

目录 前言 算法提出背景&#xff1a; 核心思想&#xff1a; 原理&#xff1a; 应用领域&#xff1a; 一、支持向量机分类&#xff08;主要变体&#xff09; 二、构建常见的支持向量机模型 基于Python 中的 Scikit-learn 库构建线性支持向量机&#xff08;SVM&#xff09; 三、向…