美文网首页
QT使用QTcpSocket实现简单的FTP文件下载

QT使用QTcpSocket实现简单的FTP文件下载

作者: wuguandong | 来源:发表于2019-10-12 13:35 被阅读0次

话不多说,直接上代码

widget.h文件

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QUrl>
#include <QTcpSocket>
#include <QRegExp>
#include <QFile>
#include <QStandardPaths>

namespace Ui {
class Widget;
}

class Widget : public QWidget
{
    Q_OBJECT

public:
    explicit Widget(QWidget *parent = nullptr);
    ~Widget();

private slots:
    //开始下载按钮槽函数
    void on_btnStart_clicked();
    //commandSocket的readyRead槽函数
    void commandReadyReadSlot();
    //dataSocket的readyRead槽函数
    void dataReadyReadSlot();

    void on_btnClear_clicked();

private:
    //发送用户名
    void sendUser();
    //发送密码
    void sendPass();
    //发送PWD
    void sendPwd();
    //获取当前目录
    void getCurrentDirectory();
    //发送TYPE
    void sendType();
    //发送SIZE
    void sendSize();
    //获取文件大小
    void getFileSize();
    //发送PASV
    void sendPasv();
    //建立dataSocket连接
    void buildDataConnection();
    //发送RETR
    void sendRetr();
    //等待传输完成
    void waitTransferComplete();
    //发送QUIT
    void sendQuit();
    //断开命令连接
    void closeCommandConnection();

private:
    Ui::Widget *ui;

    QUrl url;
    QTcpSocket *commandSocket;
    QTcpSocket *dataSocket;
    QByteArray commandBuffer;
    QByteArray dataBuffer;
    QString expectedReply;
    void (Widget::*nextAction)();
    QString currentDirectory;
    qint64 fileSize;
    qint64 receivedSize;
    QFile file;
    bool hasCreateFile;

};

#endif // WIDGET_H

widget.cpp文件

#pragma execution_character_set("utf-8")
#include "widget.h"
#include "ui_widget.h"

Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{
    ui->setupUi(this);

    this->commandSocket = new QTcpSocket(this);
    this->dataSocket = new QTcpSocket(this);
    connect(this->commandSocket, &QTcpSocket::readyRead, this, &Widget::commandReadyReadSlot);
    connect(this->dataSocket, &QTcpSocket::readyRead, this, &Widget::dataReadyReadSlot);
}

Widget::~Widget()
{
    delete ui;
}

//开始下载按钮槽函数
void Widget::on_btnStart_clicked()
{
    url.setUrl(ui->leUrl->text());

    commandSocket->connectToHost(url.host(), url.port()==-1? 21: static_cast<quint16>(url.port()));
    this->expectedReply = "220";
    if(url.userName().isEmpty()){
        url.setUserName("anonymous");
        url.setPassword("chrome@example.com");
    }
    this->nextAction = &Widget::sendUser;

    //初始化成员变量
    this->hasCreateFile = false;
    this->receivedSize = 0;

    ui->progressBar->setValue(0);
}

//commandSocket的readyRead槽函数
void Widget::commandReadyReadSlot()
{
    this->commandBuffer.clear();
    this->commandBuffer = commandSocket->readAll();
    ui->textEdit->append("收到服务器回复:" + this->commandBuffer);

    if(!this->expectedReply.isEmpty() && this->commandBuffer.mid(0,3) == this->expectedReply.toLatin1()){
        if(nextAction) (this->*nextAction)();
    }
    else{
        ui->textEdit->append( QString("错误:收到不符合期待(%1)的回应:(%2)").arg(this->expectedReply).arg(QString("").append(this->commandBuffer)) );
    }
}

//dataSocket的readyRead槽函数
void Widget::dataReadyReadSlot()
{
    this->dataBuffer.clear();
    this->dataBuffer = dataSocket->readAll();

    //写入文件
    qint64 size = file.write(this->dataBuffer);
    this->receivedSize += size;

    //更新进度条
    ui->progressBar->setValue(static_cast<int>(receivedSize / 1024));

    if(this->receivedSize >= this->fileSize){
        dataSocket->disconnectFromHost();
        dataSocket->close();
        file.close();
    }
}

//发送用户名
void Widget::sendUser()
{
    QString command = QString("USER %1\r\n").arg(url.userName());
    ui->textEdit->append("向服务器发送: " + command);
    commandSocket->write(command.toLatin1());
    this->expectedReply = "331";
    this->nextAction = &Widget::sendPass;
}

//发送密码
void Widget::sendPass()
{
    QString command = QString("PASS %1\r\n").arg(url.password());
    ui->textEdit->append("向服务器发送: " + command);
    commandSocket->write(command.toLatin1());
    this->expectedReply = "230";
    this->nextAction = &Widget::sendPwd;
}

//发送PWD
void Widget::sendPwd()
{
    QString command = "PWD\r\n";
    ui->textEdit->append("向服务器发送: " + command);
    commandSocket->write(command.toLatin1());
    this->expectedReply = "257";
    this->nextAction = &Widget::getCurrentDirectory;
}

//获取当前目录
void Widget::getCurrentDirectory()
{
    QRegExp rx(R"(".+")");
    rx.indexIn(this->commandBuffer);
    QString tmp = rx.capturedTexts().at(0);
    this->currentDirectory = tmp.mid(1,tmp.length()-2);

    this->sendType();
}

//发送TYPE
void Widget::sendType()
{
    QString command = "TYPE I\r\n";
    ui->textEdit->append("向服务器发送: " + command);
    commandSocket->write(command.toLatin1());
    this->expectedReply = "200";
    this->nextAction = &Widget::sendSize;
}

//发送SIZE
void Widget::sendSize()
{
    QString command = QString("SIZE %1%2\r\n").arg(this->currentDirectory == "/"? "": this->currentDirectory).arg(url.path());
    ui->textEdit->append("向服务器发送: " + command);
    commandSocket->write(command.toLatin1());
    this->expectedReply = "213";
    this->nextAction = &Widget::getFileSize;
}

//获取文件大小
void Widget::getFileSize()
{
    this->fileSize = commandBuffer.mid(4, commandBuffer.length()-6).toInt();

    //初始化进度条
    ui->progressBar->setMaximum(static_cast<int>(this->fileSize / 1024));

    this->sendPasv();
}

//发送PASV
void Widget::sendPasv()
{
    QString command = "PASV\r\n";
    ui->textEdit->append("向服务器发送: " + command);
    commandSocket->write(command.toLatin1());
    this->expectedReply = "227";
    this->nextAction = &Widget::buildDataConnection;
}

//建立dataSocket连接
void Widget::buildDataConnection()
{
    QRegExp rx(R"(\(\d{1,3},\d{1,3},\d{1,3},\d{1,3},\d{1,3},\d{1,3}\))");
    rx.indexIn(this->commandBuffer);
    QString tmp = rx.capturedTexts().at(0);
    QStringList list = tmp.mid(1,tmp.length()-2).split(',');

    quint16 port = static_cast<quint16>(list.at(4).toInt() * 256 + list.at(5).toInt());
    ui->textEdit->append("**建立数据连接**");
    dataSocket->connectToHost(url.host(), port);
    connect(dataSocket, &QTcpSocket::connected, [=]{
        if(!this->hasCreateFile){
            this->hasCreateFile = true;
            //创建文件
            ui->textEdit->append("**触发了connected信号**");
            file.setFileName(QStandardPaths::writableLocation(QStandardPaths::DesktopLocation).append("/").append(url.fileName()));
            bool isOk = file.open(QIODevice::WriteOnly);
            if(!isOk){
                ui->textEdit->append("错误:文件打开失败");
                return;
            }

            this->sendRetr();
        }
    });
}

//发送RETR
void Widget::sendRetr()
{
    QString command = QString("RETR %1%2\r\n").arg(this->currentDirectory).arg(url.path());
    ui->textEdit->append("向服务器发送: " + command);
    commandSocket->write(command.toLatin1());
    this->expectedReply = "150";
    this->nextAction = &Widget::waitTransferComplete;
}

//等待传输完成
void Widget::waitTransferComplete()
{
    this->expectedReply = "226";
    this->nextAction = &Widget::sendQuit;
}

//发送QUIT
void Widget::sendQuit()
{
    QString command = "QUIT\r\n";
    ui->textEdit->append("向服务器发送: " + command);
    commandSocket->write(command.toLatin1());
    this->expectedReply = "221";
    this->nextAction = &Widget::closeCommandConnection;
}

//断开命令连接
void Widget::closeCommandConnection()
{
    commandSocket->disconnectFromHost();
    commandSocket->close();
}



void Widget::on_btnClear_clicked()
{
    ui->textEdit->clear();
}

相关文章

  • QT使用QTcpSocket实现简单的FTP文件下载

    话不多说,直接上代码 widget.h文件 widget.cpp文件

  • QTcpSocket

    注意点 QTcpSocket是Qt框架中的网络通信类,它使用QSocketNotifier实现异步通信。在Qt中,...

  • QFtp源码学习及目录下载

    背景 需要在QT5中进行FTP文件下载,并需要支持整目录下载,经过对比选择,最后决定使用Qt4中的QFtp来完成我...

  • 使用comment-net工具实现FTP下载文件

    为了实现一个从FTP地址批量下载文件的功能,使用了comment-net.jar包。 主要实现代码 获得FTP链接...

  • python paramiko

    使用paramiko库实现FTP功能上传下载文件 import paramiko transport = para...

  • 【9】QT网络编程

    在QT的网路模块中提供了网络编程的相关接口来实现http的访问,其中包含了一些低级的类:QTcpSocket、QT...

  • Day07 - 作业

    一、作业:简单FTP 开发简单的FTP: 用户登陆 上传/下载文件 不同用户家目录不同 查看当前目录下文件 充分使...

  • sftp命令

    sftp 交互式文件传输工具 用法和传统的 ftp 工具相似 利用 ssh 服务实现安全的文件上传和下载 使用 l...

  • 2022-02-19 pyftpdlib-FTP复制文件

    方法一:使用requests下载文件,再上传 方法二:使用ftp模块下载,然后再上传

  • python生成简单的FTP弱口令扫描

    前言 Ftp这个类实现了Ftp客户端的大多数功能,比如连接Ftp服务器、查看服务器中的文件、上传、下载文件等功能,...

网友评论

      本文标题:QT使用QTcpSocket实现简单的FTP文件下载

      本文链接:https://www.haomeiwen.com/subject/edghyctx.html