Qt实现tftp客户端

分享一个之前用qt实现的tftp客户端,希望能给有需要的同学一些帮助。

完整的项目(可执行程序及源代码)下载地址:完整项目tftp v1.0

源代码文件各自内容如下:

  • mythread.cpp:实现tftp的主逻辑。
  • widget.cpp:实现操作页面。

运行界面如下,支持put和get功能。

下面列出所有的代码片段和项目配置文件。

mythread.h

#ifndef MYTHREAD_H
#define MYTHREAD_H#include 
#include 
#include 
#include #define DATA_RECIVE_FLAG    0x80
#define ACK_RECIVE_FLAG     0x82
#define ERR_RECIVE_FLAG     0x84#define DATA_SEND_FLAG      0x81
#define ACK_SEND_FLAG       0x83
#define RRQ_SEND_FLAG       0x85
#define WRQ_SEND_FLAG       0x87#define LOBYTE(w)       (w & 0xFF)
#define HIBYTE(w)       ((w >> 8)&0xFF)
#define MAKEWORD(l,h)   ((h << 8)|l)class QUdpSocket;enum {RRQ = 1,WRQ,DATA,ACK,ERROR
};
struct code{quint16 Opcode;QString path;QString fileName;quint16 blocks;
};
struct msg{quint8 flag;QString messageBuf;
};class MyThread : public QThread
{Q_OBJECT
public:QUdpSocket *tftpclient;quint8 Eof;quint8 timeOutCount;quint8 maxRetryCount;quint16 port;quint16 peerPort;quint16 currentPort;quint16 errcode;quint16 cBlocks;quint64 cLen;quint64 filesize;QTimer timer;QByteArray Datagram;int timId;int trMod;QHostAddress serverIp;struct code Code;QString mode;QFile *file;struct msg Msg;MyThread();void run();void timerReset();void timerStop();void GetErrMsg();void sendMsg(quint8 flag);void DoReciveData(char *pct,quint64);void DoReciveAck(char *pct);void DoReciveErr(char *pct);void SendFile(QByteArray *Datagram);void SendData(quint16 port);void SendReadReq();void SendWriteReq();void SendAck();void Clear();QHostAddress getServerIp();signals:void timeOut();void showMsg();void transOver();private slots:void on_timeOut();void ReciveData();
};#endif // MYTHREAD_H

mythread.cpp

#include "mythread.h"
#include 
#include 
#include MyThread::MyThread()
{mode = "octet";port = 69;cBlocks = 0;cLen = 0;Eof=0;timeOutCount=0;currentPort=0;maxRetryCount=10;Code.blocks =0;Code.Opcode =0;tftpclient = new QUdpSocket;tftpclient->bind(6666/*,QUdpSocket::ShareAddress | QUdpSocket::ReuseAddressHint*/);connect(tftpclient,SIGNAL(readyRead()),this,SLOT(ReciveData()));connect(&timer,SIGNAL(timeout()), this, SLOT(on_timeOut()) );
}void MyThread::Clear()
{cBlocks = 0;cLen = 0;Eof=0;Code.blocks =0;Code.Opcode =0;
}void MyThread::SendWriteReq()
{Code.Opcode = WRQ;file = new QFile(Code.path+"/"+Code.fileName);if (!file->exists()) {qDebug()<<"file not exit!";return;}Eof=0;filesize = file->size();SendData(port);
}void MyThread::SendReadReq()
{Code.Opcode = RRQ;file = new QFile(Code.path+"/"+Code.fileName);if (file->exists()) {file->remove();file->setFileName(Code.path+"/"+Code.fileName);qDebug()<<"file exit & rm";}SendData(port);
}void MyThread::SendAck()
{Code.Opcode = ACK;if (Code.blocks-1 == cBlocks) {cBlocks = Code.blocks;sendMsg(ACK_SEND_FLAG);SendData(peerPort);}
}void MyThread::run()
{while(1){qDebug()<< "start thread";sleep(5);}
}void MyThread::SendFile(QByteArray *Datagram)
{quint8 fun =0;quint8 hi = HIBYTE(Code.blocks);quint8 lo = LOBYTE(Code.blocks);quint8 val;quint16 i;Datagram->clear();Datagram->append(fun);Datagram->append(DATA);Datagram->append(hi);Datagram->append(lo);file->open(QIODevice::ReadOnly);file->seek(cLen);QDataStream in(file);for(i=0;(i < 512)&&(i<(filesize-cLen));i++){in >> val;Datagram->append(val);}file->close();cLen += i;sendMsg(DATA_SEND_FLAG);if (i < 512){Eof=1;//文件传输结束cLen=0;Code.blocks=0;}
}void MyThread::GetErrMsg()
{switch (errcode) {case 1:Msg.messageBuf.append("文件未找到!");break;case 2:Msg.messageBuf.append("非法操作!");break;case 3:Msg.messageBuf.append("磁盘满!");break;case 4:Msg.messageBuf.append("非法操作码!");break;case 5:Msg.messageBuf.append("未知发送ID!");break;case 6:Msg.messageBuf.append("文件已经存在!");break;case 7:Msg.messageBuf.append("没有当前用户!");break;default:Msg.messageBuf.append("未定义错误!");break;}
}void MyThread::DoReciveErr(char *pct)
{errcode = MAKEWORD((quint8)pct[3],(quint8)pct[2]);sendMsg(ERR_RECIVE_FLAG);
}void MyThread::DoReciveAck(char *pct)
{quint16 blocks = MAKEWORD((quint8)pct[3],(quint8)pct[2]);if(Code.blocks == blocks) {Code.blocks += 1;}Code.Opcode=DATA;sendMsg(ACK_RECIVE_FLAG);if (Eof) {emit transOver();timerStop();return;}SendData(peerPort);
}void MyThread::sendMsg(quint8 flag)
{char temval[5]={0};Msg.flag = flag;if ((flag & 0x81) == 0x81)Msg.messageBuf.append("发送:");elseMsg.messageBuf.append("接收:");switch(flag) {case DATA_RECIVE_FLAG:Msg.messageBuf.append("数据包 ");sprintf(temval,"%d",Code.blocks);Msg.messageBuf.append(temval);break;case DATA_SEND_FLAG:Msg.messageBuf.append("数据包 ");sprintf(temval,"%d",Code.blocks);Msg.messageBuf.append(temval);break;case ACK_SEND_FLAG:Msg.messageBuf.append("响应 ");sprintf(temval,"%d",Code.blocks);Msg.messageBuf.append(temval);break;case ACK_RECIVE_FLAG:Msg.messageBuf.append("响应 ");sprintf(temval,"%d",Code.blocks);Msg.messageBuf.append(temval);break;case RRQ_SEND_FLAG:Msg.messageBuf.append("读文件请求");break;case WRQ_SEND_FLAG:Msg.messageBuf.append("写文件请求");break;case ERR_RECIVE_FLAG:GetErrMsg();break;default:return;}Msg.messageBuf.append("\n");emit showMsg();
}void MyThread::DoReciveData(char *pct,quint64 len)
{if(file->open(QIODevice::WriteOnly|QIODevice::Append))qDebug()<< "openfile ok";elsereturn;QDataStream out(file);Code.blocks = MAKEWORD((quint8)pct[3],(quint8)pct[2]);pct +=4;for (quint16 i=0;iclose();sendMsg(DATA_RECIVE_FLAG);SendAck();if (len < 516){timerStop();Code.blocks=0;cBlocks =0;emit transOver();delete file;}
}void MyThread::ReciveData()
{while(tftpclient->hasPendingDatagrams()){QByteArray datagram;QHostAddress addr;datagram.resize(tftpclient->pendingDatagramSize());tftpclient->readDatagram(datagram.data(), datagram.size(),&addr,&peerPort);char *pct = (char*)datagram.data();quint16 opcode = MAKEWORD((quint8)pct[1],(quint8)pct[0]);quint64 len = datagram.length();switch(opcode) {case RRQ:case WRQ:break;case DATA:timerReset();DoReciveData(pct,len);break;case ACK:timerReset();DoReciveAck(pct);break;case ERROR:DoReciveErr(pct);timerStop();break;default:break;}}
}void MyThread::SendData(quint16 port)
{quint8 fun =0;quint8 hi = HIBYTE(Code.blocks);quint8 lo = LOBYTE(Code.blocks);currentPort = port;switch(Code.Opcode) {case RRQ:Datagram.clear();Datagram.append(fun);Datagram.append(RRQ);Datagram.append(Code.fileName);Datagram.append(fun);Datagram.append(mode);Datagram.append(fun);sendMsg(RRQ_SEND_FLAG);break;case WRQ:Datagram.clear();Datagram.append(fun);Datagram.append(WRQ);Datagram.append(Code.fileName);Datagram.append(fun);Datagram.append(mode);Datagram.append(fun);sendMsg(WRQ_SEND_FLAG);break;case DATA:SendFile(&Datagram);break;case ACK:Datagram.clear();Datagram.append(fun);Datagram.append(ACK);Datagram.append(hi);Datagram.append(lo);break;case ERROR:Datagram.clear();Datagram.append(fun);Datagram.append(ERROR);break;default:break;}tftpclient->writeDatagram(Datagram,Datagram.length(),getServerIp(),port);
}void MyThread::timerReset()
{timeOutCount = 0;timer.start(1000);
}void MyThread::timerStop()
{timeOutCount=0;timer.stop();
}void MyThread::on_timeOut()
{SendData(currentPort);timeOutCount ++;if(timeOutCount > maxRetryCount) {timerStop();emit timeOut();}
}QHostAddress MyThread::getServerIp()
{return serverIp;
}

widget.h

#ifndef WIDGET_H
#define WIDGET_H#include 
#include 
#include "mythread.h"namespace Ui {
class Widget;
}enum {get_mod=2,put_mod=3
};class Widget : public QWidget
{Q_OBJECTpublic:explicit Widget(QWidget *parent = 0);~Widget();quint8 parOkFlag;quint8 modflag;MyThread *thread;private slots:void DoTimeOut();void on_showMsg();void on_transOver();void on_lineEdit_returnPressed();void on_pushButton_clicked();void on_pushButton_2_clicked();void on_toolButton_clicked();void on_comboBox_currentIndexChanged(int index);private:Ui::Widget *ui;
};#endif // WIDGET_H

widget.cpp

#include "widget.h"
#include "ui_widget.h"
#include 
#include 
#include Widget::Widget(QWidget *parent) :QWidget(parent),ui(new Ui::Widget)
{parOkFlag =0;//参数正确标志modflag =get_mod;//初始化为get模式thread = new MyThread();ui->setupUi(this);connect(thread,SIGNAL(transOver()),this,SLOT(on_transOver()),Qt::QueuedConnection);connect(thread,SIGNAL(showMsg()),this,SLOT(on_showMsg()));connect(thread,SIGNAL(timeOut()),this,SLOT(DoTimeOut()));ui->textBrowser->append("Version 1.0");ui->textBrowser->append("Author: dhm@zxe-china.com");
}Widget::~Widget()
{delete ui;
}void Widget::DoTimeOut()
{QMessageBox::warning(this,"错误","传输失败 请求超时!",QMessageBox::Abort);
}void Widget::on_lineEdit_returnPressed()
{qDebug() << ui->lineEdit->text().toUInt();
}void Widget::on_pushButton_clicked()
{thread->serverIp = ui->lineEdit->text();thread->trMod = ui->comboBox->currentIndex();if(modflag==get_mod) {thread->Code.path = ui->lineEdit_3->text();thread->Code.fileName = ui->lineEdit_2->text();} else if (modflag == put_mod) {QFileInfo info = ui->lineEdit_3->text();thread->Code.path = info.absolutePath();thread->Code.fileName = info.fileName();}if (thread->serverIp.isNull()) {QMessageBox::warning(this,"警告","IP地址不能为空!",QMessageBox::Abort);parOkFlag=0;}else if (thread->Code.fileName.isEmpty()) {QMessageBox::warning(this,"警告","文件名不能为空!",QMessageBox::Abort);parOkFlag=0;}else if (thread->Code.path.isEmpty()) {if(modflag == get_mod)QMessageBox::warning(this,"警告","请选择保存位置!",QMessageBox::Abort);if(modflag == put_mod)QMessageBox::warning(this,"警告","请选择文件!",QMessageBox::Abort);parOkFlag=0;}else {parOkFlag =1;}qDebug()<<"currentindex"<comboBox->currentIndex();qDebug() << thread->serverIp;qDebug() << thread->Code.fileName;
}void Widget::on_pushButton_2_clicked()
{if (parOkFlag) {thread->Clear();thread->timer.start(1000);if (thread->trMod == 0)thread->SendReadReq();elsethread->SendWriteReq();parOkFlag =0;}
}void Widget::on_showMsg()
{ui->textBrowser->append(thread->Msg.messageBuf);thread->Msg.messageBuf.clear();thread->Msg.flag=0;
}void Widget::on_transOver()
{QMessageBox::information(this,"提示","文件传输完成!",QMessageBox::Ok);
}void Widget::on_toolButton_clicked()
{if (modflag==get_mod){ui->lineEdit_3->setText(QFileDialog::getExistingDirectory(this));} else if (modflag==put_mod){ui->lineEdit_3->setText(QFileDialog::getOpenFileName(this));}
}void Widget::on_comboBox_currentIndexChanged(int index)
{if (index == 0) {//get模式ui->label_4->setText("存储位置:");ui->lineEdit_2->clear();ui->lineEdit_3->clear();ui->lineEdit_2->setEnabled(true);modflag =get_mod;}else if (index == 1) {ui->label_4->setText("选择文件:");ui->lineEdit_2->clear();ui->lineEdit_3->clear();ui->lineEdit_2->setDisabled(true);modflag =put_mod;}
}

main.cpp

#include "widget.h"
#include 
#include int main(int argc, char *argv[])
{QApplication a(argc, argv);Widget w;w.show();return a.exec();
}

项目文件tftpclient.pro

#-------------------------------------------------
#
# Project created by QtCreator 2017-04-08T19:47:47
#
#-------------------------------------------------QT       += core gui
QT       += networkgreaterThan(QT_MAJOR_VERSION, 4): QT += widgetsTARGET = tftpclient
TEMPLATE = appSOURCES += main.cpp\widget.cpp \mythread.cppHEADERS  += widget.h \mythread.hFORMS    += widget.uiRC_FILE += myico.rc

ui_widget.h

/********************************************************************************
** Form generated from reading UI file 'widget.ui'
**
** Created by: Qt User Interface Compiler version 5.8.0
**
** WARNING! All changes made in this file will be lost when recompiling UI file!
********************************************************************************/#ifndef UI_WIDGET_H
#define UI_WIDGET_H#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include QT_BEGIN_NAMESPACEclass Ui_Widget
{
public:QLineEdit *lineEdit;QLabel *label;QLineEdit *lineEdit_2;QLabel *label_2;QPushButton *pushButton;QPushButton *pushButton_2;QComboBox *comboBox;QLabel *label_3;QTextBrowser *textBrowser;QToolButton *toolButton;QLabel *label_4;QLineEdit *lineEdit_3;void setupUi(QWidget *Widget){if (Widget->objectName().isEmpty())Widget->setObjectName(QStringLiteral("Widget"));Widget->resize(447, 380);lineEdit = new QLineEdit(Widget);lineEdit->setObjectName(QStringLiteral("lineEdit"));lineEdit->setGeometry(QRect(100, 38, 101, 20));lineEdit->setContextMenuPolicy(Qt::ActionsContextMenu);lineEdit->setAutoFillBackground(false);lineEdit->setInputMethodHints(Qt::ImhNone);lineEdit->setCursorPosition(0);lineEdit->setCursorMoveStyle(Qt::LogicalMoveStyle);label = new QLabel(Widget);label->setObjectName(QStringLiteral("label"));label->setGeometry(QRect(41, 38, 48, 16));label->setTextFormat(Qt::AutoText);lineEdit_2 = new QLineEdit(Widget);lineEdit_2->setObjectName(QStringLiteral("lineEdit_2"));lineEdit_2->setGeometry(QRect(100, 70, 101, 20));label_2 = new QLabel(Widget);label_2->setObjectName(QStringLiteral("label_2"));label_2->setGeometry(QRect(41, 70, 48, 16));pushButton = new QPushButton(Widget);pushButton->setObjectName(QStringLiteral("pushButton"));pushButton->setGeometry(QRect(280, 50, 91, 23));pushButton_2 = new QPushButton(Widget);pushButton_2->setObjectName(QStringLiteral("pushButton_2"));pushButton_2->setGeometry(QRect(280, 90, 91, 23));comboBox = new QComboBox(Widget);comboBox->setObjectName(QStringLiteral("comboBox"));comboBox->setGeometry(QRect(100, 100, 44, 20));label_3 = new QLabel(Widget);label_3->setObjectName(QStringLiteral("label_3"));label_3->setGeometry(QRect(41, 100, 36, 16));textBrowser = new QTextBrowser(Widget);textBrowser->setObjectName(QStringLiteral("textBrowser"));textBrowser->setGeometry(QRect(41, 189, 371, 181));toolButton = new QToolButton(Widget);toolButton->setObjectName(QStringLiteral("toolButton"));toolButton->setGeometry(QRect(210, 130, 21, 18));label_4 = new QLabel(Widget);label_4->setObjectName(QStringLiteral("label_4"));label_4->setGeometry(QRect(40, 130, 54, 12));lineEdit_3 = new QLineEdit(Widget);lineEdit_3->setObjectName(QStringLiteral("lineEdit_3"));lineEdit_3->setGeometry(QRect(100, 130, 101, 20));
#ifndef QT_NO_SHORTCUTlabel->setBuddy(lineEdit);label_2->setBuddy(lineEdit_2);label_3->setBuddy(comboBox);label_4->setBuddy(lineEdit_3);
#endif // QT_NO_SHORTCUTretranslateUi(Widget);QMetaObject::connectSlotsByName(Widget);} // setupUivoid retranslateUi(QWidget *Widget){Widget->setWindowTitle(QApplication::translate("Widget", "TftpTools", Q_NULLPTR));lineEdit->setInputMask(QApplication::translate("Widget", "000.000.000.000", Q_NULLPTR));lineEdit->setPlaceholderText(QString());label->setText(QApplication::translate("Widget", "IP\345\234\260\345\235\200\357\274\232", Q_NULLPTR));label_2->setText(QApplication::translate("Widget", "\346\226\207\344\273\266\345\220\215\357\274\232", Q_NULLPTR));pushButton->setText(QApplication::translate("Widget", "\347\241\256\345\256\232", Q_NULLPTR));pushButton_2->setText(QApplication::translate("Widget", "\345\220\257\345\212\250", Q_NULLPTR));comboBox->clear();comboBox->insertItems(0, QStringList()<< QApplication::translate("Widget", "Get", Q_NULLPTR)<< QApplication::translate("Widget", "Put", Q_NULLPTR));label_3->setText(QApplication::translate("Widget", "\346\250\241\345\274\217\357\274\232", Q_NULLPTR));toolButton->setText(QApplication::translate("Widget", "...", Q_NULLPTR));label_4->setText(QApplication::translate("Widget", "\345\255\230\345\202\250\344\275\215\347\275\256\357\274\232", Q_NULLPTR));} // retranslateUi};namespace Ui {class Widget: public Ui_Widget {};
} // namespace UiQT_END_NAMESPACE#endif // UI_WIDGET_H

widget.ui


Widget00447380TftpTools1003810120Qt::ActionsContextMenufalseQt::ImhNone000.000.000.0000Qt::LogicalMoveStyle41384816IP地址:Qt::AutoTextlineEdit100701012041704816文件名:lineEdit_2280509123确定280909123启动1001004420GetPut411003616模式:comboBox411893711812101302118...401305412存储位置:lineEdit_310013010120

 


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部