Qt实现TFTP Server和 TFTP Client(三)

3.2 Client

Client包括下面3个类:

  • ClientSocke
  • TFtpClient
  • TFtpClientWidget
3.2.1 ClientSocke

ClientSocke从BaseUdp派生实现write接口.

3.2.1.1 ClientSocke定义
#include "baseudp.h"

class QUdpSocket;
class ClientSocket : public BaseUdp
{
public:
    ClientSocket(QUdpSocket* socket)
    : socket_(socket)
    {}

    uint32_t write(const char* data, size_t size) override;
private:
    QUdpSocket* socket_;
};

成员函数说明:

  • write 重载函数,实现父类BaseUdp中定义的write接口。
3.2.1.2 ClientSocke实现
#include "clientsocket.h"
#include <QUdpSocket>

uint32_t ClientSocket::write(const char* data, size_t size)
{
    return socket_->write(data, size);
}

函数实现说明:

  • 直接调用QUdpSocket对象的write接口。
3.2.2 TFtpClient

TFtpClient类通过TFtpClientFile类实现一个TFTP客户端,实现上下载文件。

3.2.2.1 TFtpClient定义
class QUdpSocket;
class TFtpClient : public QObject
{
    Q_OBJECT
public:
    explicit TFtpClient(QObject *parent = nullptr);

    void setHostPort(QString const& host, quint16 port);
    void getFile(QString const& localFileName, QString const& remoteFileName);
    void putFile(QString const& localFileName, QString const& remoteFileName);

    bool isPut() const { return isPut_; }
public slots:
    void stopFileTransfer();
signals:
    void started();
    void progress(quint64 bytes, quint64 total);
    void error(QString const& text);
    void finished();
private slots:
    void connected();
    void connectError(QAbstractSocket::SocketError error);
    void readPendingDatagrams();
private:
    QUdpSocket* socket;
    QString host_;
    quint16 port_;
    QString localFileName_;
    QString remoteFileName_;
    TFtpClientFile::Ptr tftpFile_;
    bool isPut_ = false;
};

成员函数说明:

  • setHostPort 配置TFTP服务器的IP地址和端口.
  • getFile 从TFTP服务器下载文件.
  • putFile 向TFTP服务器上传文件.
  • isPut 是否是上传
  • stopFileTransfer 终止文件传输

信号说明:

  • started 文件传输开始信号
  • progress 传输进度信号
  • error 错误信号
  • finished 传输完成信号

槽函数说明:

  • connected 与TFTP服用器连接成功后的处理函数
  • connectError 与TFTP服用器连接失败后的处理函数
  • readPendingDatagrams 从TFTP服用器读数处理函数
3.2.2.2 TFtpClient实现
  • 构造函数
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)));
}

函数说明:

  • 创建QUdpSocket对象socket

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

  • setHostPort/getFile/putFile

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_);
}

函数说明:

  • setHostPort 保存主机地址和端接口

  • getFile 保存本地文件名和远程文件名,设置为下载,连接TFTP服务器

  • putFile 保存本地文件名和远程文件名,设置为上传,连接TFTP服务器

  • stopFileTransfer/connected/connectError/readPendingDatagrams

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);
    else
        isOK = tftpFile_->getFile(localFileName_.toStdString(),
                           remoteFileName_.toStdString(), TFtp::BINARY);
    if(!isOK)
        emit error("Local File not Found");
    else
        emit 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()));
                else
                    emit finished();
            }
        }
    }
}

函数说明:

  • stopFileTransfer 与TFTP服务器断开连接,终止文件传输。
  • connected 连接上TFTP服务器后,创建TFtpClientFile对象,开始上传/下载文件
  • connectError 与TFTP服务器连接失败,发送连接失败信号量。
  • readPendingDatagrams 从TFTP服务器读取数据给TFtpClientFile对象处理,如果传输结束,有错误发送error信号,没错误发送finished信号。
3.2.3 TFtpClientWidget

TFtpClientWidget从QWidget派生一个窗口类,负责发起上下载文件,并显示文件传输进度等界面操作。

3.2.3.1 TFtpClientWidget定义
class TFtpClient;
class TFtpClientWidget : public QWidget
{
    Q_OBJECT

public:
    TFtpClientWidget(QWidget *parent = nullptr);
    ~TFtpClientWidget();

private slots:
    void onGetFile();
    void onPutFile();
    void onStarted();
    void onProgress(quint64 bytes, quint64 total);
    void onStop();
    void onFinished();
    void onError(QString const& error);
    void onSelectLocalFile();
private:
    void enableButtons(bool enable);
private:
    Ui::TFtpClientWidget *ui;
    TFtpClient* tftpClient;
};
3.2.3.2 TFtpClientWidget实现
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!");
    else
        QMessageBox::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.2.4 PutFile序列图

PutFile序列图

3.2.4 GetFile序列图

GetFile序列图

Qt实现TFTP Server和 TFTP Client(二)Qt实现TFTP Server和 TFTP Client(四)

  • 14
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

flysnow010

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值