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.pswp.cn/web/66782.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/66782.shtml
英文地址,請注明出處:http://en.pswp.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;匹配…