Qt实现tftp客户端

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

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

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

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

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

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

mythread.h

#ifndef MYTHREAD_H
#define MYTHREAD_H

#include <QThread>
#include <QtNetwork>
#include <QUdpSocket>
#include <QTime>

#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 <QDebug>
#include <QFile>
#include <QDataStream>

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("发送:");
    else
        Msg.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";
    else
        return;
    QDataStream out(file);
    Code.blocks = MAKEWORD((quint8)pct[3],(quint8)pct[2]);
    pct +=4;
    for (quint16 i=0;i<len-4;i++)
        out << *(uchar *)pct++;
    file->close();
    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 <QWidget>
#include <QLineEdit>
#include "mythread.h"

namespace Ui {
class Widget;
}

enum {
  get_mod=2,
  put_mod=3
};

class Widget : public QWidget
{
    Q_OBJECT
    
public:
    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 <QDebug>
#include <QMessageBox>
#include <QFileDialog>

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"<<ui->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();
        else
            thread->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 <QApplication>
#include <QTextCodec>

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       += network

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

TARGET = tftpclient
TEMPLATE = app


SOURCES += main.cpp\
        widget.cpp \
    mythread.cpp

HEADERS  += widget.h \
    mythread.h

FORMS    += widget.ui

RC_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 <QtCore/QVariant>
#include <QtWidgets/QAction>
#include <QtWidgets/QApplication>
#include <QtWidgets/QButtonGroup>
#include <QtWidgets/QComboBox>
#include <QtWidgets/QHeaderView>
#include <QtWidgets/QLabel>
#include <QtWidgets/QLineEdit>
#include <QtWidgets/QPushButton>
#include <QtWidgets/QTextBrowser>
#include <QtWidgets/QToolButton>
#include <QtWidgets/QWidget>

QT_BEGIN_NAMESPACE

class 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_SHORTCUT
        label->setBuddy(lineEdit);
        label_2->setBuddy(lineEdit_2);
        label_3->setBuddy(comboBox);
        label_4->setBuddy(lineEdit_3);
#endif // QT_NO_SHORTCUT

        retranslateUi(Widget);

        QMetaObject::connectSlotsByName(Widget);
    } // setupUi

    void 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 Ui

QT_END_NAMESPACE

#endif // UI_WIDGET_H

widget.ui

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>Widget</class>
 <widget class="QWidget" name="Widget">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>447</width>
    <height>380</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>TftpTools</string>
  </property>
  <widget class="QLineEdit" name="lineEdit">
   <property name="geometry">
    <rect>
     <x>100</x>
     <y>38</y>
     <width>101</width>
     <height>20</height>
    </rect>
   </property>
   <property name="contextMenuPolicy">
    <enum>Qt::ActionsContextMenu</enum>
   </property>
   <property name="autoFillBackground">
    <bool>false</bool>
   </property>
   <property name="inputMethodHints">
    <set>Qt::ImhNone</set>
   </property>
   <property name="inputMask">
    <string>000.000.000.000</string>
   </property>
   <property name="cursorPosition">
    <number>0</number>
   </property>
   <property name="placeholderText">
    <string extracomment="IP地址"/>
   </property>
   <property name="cursorMoveStyle">
    <enum>Qt::LogicalMoveStyle</enum>
   </property>
  </widget>
  <widget class="QLabel" name="label">
   <property name="geometry">
    <rect>
     <x>41</x>
     <y>38</y>
     <width>48</width>
     <height>16</height>
    </rect>
   </property>
   <property name="text">
    <string>IP地址:</string>
   </property>
   <property name="textFormat">
    <enum>Qt::AutoText</enum>
   </property>
   <property name="buddy">
    <cstring>lineEdit</cstring>
   </property>
  </widget>
  <widget class="QLineEdit" name="lineEdit_2">
   <property name="geometry">
    <rect>
     <x>100</x>
     <y>70</y>
     <width>101</width>
     <height>20</height>
    </rect>
   </property>
  </widget>
  <widget class="QLabel" name="label_2">
   <property name="geometry">
    <rect>
     <x>41</x>
     <y>70</y>
     <width>48</width>
     <height>16</height>
    </rect>
   </property>
   <property name="text">
    <string>文件名:</string>
   </property>
   <property name="buddy">
    <cstring>lineEdit_2</cstring>
   </property>
  </widget>
  <widget class="QPushButton" name="pushButton">
   <property name="geometry">
    <rect>
     <x>280</x>
     <y>50</y>
     <width>91</width>
     <height>23</height>
    </rect>
   </property>
   <property name="text">
    <string>确定</string>
   </property>
  </widget>
  <widget class="QPushButton" name="pushButton_2">
   <property name="geometry">
    <rect>
     <x>280</x>
     <y>90</y>
     <width>91</width>
     <height>23</height>
    </rect>
   </property>
   <property name="text">
    <string>启动</string>
   </property>
  </widget>
  <widget class="QComboBox" name="comboBox">
   <property name="geometry">
    <rect>
     <x>100</x>
     <y>100</y>
     <width>44</width>
     <height>20</height>
    </rect>
   </property>
   <item>
    <property name="text">
     <string>Get</string>
    </property>
   </item>
   <item>
    <property name="text">
     <string>Put</string>
    </property>
   </item>
  </widget>
  <widget class="QLabel" name="label_3">
   <property name="geometry">
    <rect>
     <x>41</x>
     <y>100</y>
     <width>36</width>
     <height>16</height>
    </rect>
   </property>
   <property name="text">
    <string>模式:</string>
   </property>
   <property name="buddy">
    <cstring>comboBox</cstring>
   </property>
  </widget>
  <widget class="QTextBrowser" name="textBrowser">
   <property name="geometry">
    <rect>
     <x>41</x>
     <y>189</y>
     <width>371</width>
     <height>181</height>
    </rect>
   </property>
  </widget>
  <widget class="QToolButton" name="toolButton">
   <property name="geometry">
    <rect>
     <x>210</x>
     <y>130</y>
     <width>21</width>
     <height>18</height>
    </rect>
   </property>
   <property name="text">
    <string>...</string>
   </property>
  </widget>
  <widget class="QLabel" name="label_4">
   <property name="geometry">
    <rect>
     <x>40</x>
     <y>130</y>
     <width>54</width>
     <height>12</height>
    </rect>
   </property>
   <property name="text">
    <string>存储位置:</string>
   </property>
   <property name="buddy">
    <cstring>lineEdit_3</cstring>
   </property>
  </widget>
  <widget class="QLineEdit" name="lineEdit_3">
   <property name="geometry">
    <rect>
     <x>100</x>
     <y>130</y>
     <width>101</width>
     <height>20</height>
    </rect>
   </property>
  </widget>
 </widget>
 <layoutdefault spacing="6" margin="11"/>
 <resources/>
 <connections/>
</ui>

 

  • 6
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 12
    评论
Qt是一个跨平台的C++应用程序开发框架,可以用于开发各种类型的应用程序,包括服务器应用程序。TFTP(Trivial File Transfer Protocol)是一种简化的文件传输协议,在Qt中可以通过实现相关的网络类来实现TFTP服务器。 首先,我们需要创建一个Qt的服务器应用程序。可以使用Qt的网络模块,包括QTcpServer和QTcpSocket类来实现QTcpServer用于监听和接受客户端的连接请求,QTcpSocket用于处理与客户端的通信。 在TFTP中,服务器应该提供一些基本的操作,例如读取文件(RRQ)和写入文件(WRQ)。为了实现这些操作,我们可以在服务器应用程序中使用QTcpSocket的readyRead信号来读取客户端发送的请求,并根据请求类型进行相应的处理。 例如,当收到RRQ请求时,服务器应该打开相应的文件并读取内容,然后通过QTcpSocket的write方法将文件内容发送给客户端。当收到WRQ请求时,服务器应该创建相应的文件,并通过QTcpSocket的read方法接收客户端发送过来的文件内容,然后写入到文件中。 此外,TFTP还包含一些其他的操作,例如错误报告(ERROR),服务器可选参数(OACK)等。我们可以通过在服务器应用程序中实现相应的逻辑来处理这些操作。 总结起来,要在Qt实现TFTP服务器,我们需要使用Qt的网络模块创建一个服务器应用程序,通过接收和处理客户端的请求,实现TFTP的基本操作。同时,还需要考虑处理错误报告和其他可选参数。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值