Qt编程9:QFtp断点续传(普通文件)

来源:互联网 发布:凯立德端口波特率查看 编辑:程序博客网 时间:2024/05/07 18:27

首先明确一点:实现ftp断点续传,需要服务器支持,我使用的是CentOS 下的vsftpd作为ftp服务器。

 

  FTP连接一般是有两个连接,一种连接时客户端C与服务器端S传送命令,一种连接是用于数据的传输。而FTP连接支持两种模式

  Port模式(主动模式):涉及到的端口号有21和20,当客户端C向服务器端S通过端口21发送请求链接时,服务器端接收连接,并打开一条命令链路。当客户端需要传输数据时,便会通过命令链路向服务器端发送PORT命令请求:我打开了xxx端口,你连接我吧。服务器端接受请求,通过端口号为21向客户端xxx端口建立一条数据传输链路发送数据。

  passiv模式(被动模式):客户端C向服务器端(端口21)发送请求连接,服务器端接收并打开一条命令链路。当客户端需要传输数据时,会通过命令链路像服务器端发送passiv命令:我打开了XXX端口,你连接我吧,服务器端接受请求,从端口1024-5000中随机选择一个端口与客户端建立链接,并发送命令:我打开了XXX端口,你过来链接吧,客户端接受后就向该端口发送数据。

由此可知,port模式是客户端打开一个本地端口,等待服务器端进行数据连接,而passiv模式是由服务器打开一个端口,等待客户端进行数据连接。


QFtp具有文件上传以及下载功能,

但是对于文件的续传支持上不好,因此 我使用Qt5.2.1编译器,从网络上下载了QFtp的实现,对其进行修改。目前为止,可以实现文件的续传功能。

 

QFtp默认采用(PASV)被动模式进行文件传输

QFtp续传:http://download.csdn.net/detail/jiezhj/7528025

以下是我封装的ftpManager

//头文件

#ifndef FTPMANAGER_H#define FTPMANAGER_H#include <QObject>#include <QDebug>#include <QThread>#include <QFile>#include <QTcpSocket>#include "qftp.h"class FtpManager : public QObject{    Q_OBJECTpublic:    explicit FtpManager(QString _host, QString userName = "", QString passWd = "",qint16 _port = 21,QObject *parent = 0);    ~FtpManager();signals:    void G_getProgressVal(int);public slots:    void S_commandFinish(int,bool);    void S_upDateProgress(qint64,qint64);    void S_abort();    void S_dloadFile(QString _remoteFile,QString _localFile,bool isRese = false);    void S_uloadFile(QString _localFile,QString _remoteFile,bool isRese = false);private:    QString         m_userName;    QString         m_passwd;    QFtp            *myFtp;    QFile           *m_File;    bool            m_IsOpenFile;};#endif // FTPMANAGER_H


//实现

#include "ftpmanager.h"class FtpManager;FtpManager::FtpManager(QString _host, QString userName, QString passWd, qint16 _port, QObject *parent):    QObject(parent),    m_userName(userName),    m_passwd(passWd),    m_File(0),    m_IsOpenFile(false){    //构建ftp对象    myFtp = new QFtp(this);    //连接ftp服务器    myFtp->connectToHost(_host,_port);    //进度条显示    connect(myFtp,SIGNAL(dataTransferProgress(qint64,qint64)),            SLOT(S_upDateProgress(qint64,qint64)));    //状态显示    connect(myFtp,SIGNAL(commandFinished(int,bool)),            SLOT(S_commandFinish(int,bool)));}FtpManager::~FtpManager(){    delete myFtp;}//停止Ftp动作void FtpManager::S_abort(){    myFtp->abort();}//下载文件(当isRese==true为续传下载)void FtpManager::S_dloadFile(QString _remoteFile,QString _localFile,bool isRese){    m_File = new QFile(_localFile);    if(!isRese)    {        qDebug() << tr("文件%1的普通下载... ...").arg(_remoteFile);        if(m_File->open(QIODevice::WriteOnly))        {            m_IsOpenFile = true;            myFtp->get(_remoteFile,m_File);        }        else        {            delete m_File;            m_File = NULL;            qDebug() << tr("本地文件%1打开失败!").arg(_localFile);        }    }    else    {        qDebug() << tr("文件%1的续传下载... ...").arg(_remoteFile);        if(m_File->open(QIODevice::Append))        {            m_IsOpenFile = true;            myFtp->rawCommand(tr("REST %1").arg(m_File->size()));            myFtp->m_isConLoad = true;          //设置当前现在为续传            myFtp->get(_remoteFile,m_File);        }        else        {            delete m_File;            m_File = NULL;            qDebug() << tr("本地文件%1打开失败!").arg(_localFile);        }    }}//上传文件(当isRese==true为续传上传)void FtpManager::S_uloadFile(QString _localFile,QString _remoteFile,bool isRese){    m_File = new QFile(_localFile);    if(m_File->open(QIODevice::ReadOnly))    {        m_IsOpenFile = true;        if(!isRese)        {            qDebug() << tr("文件%1的普通上传... ...").arg(_localFile);            myFtp->put(m_File,_remoteFile);                                     //上传        }        else        {            qDebug() << tr("文件%1的续传... ...").arg(_localFile);            //在QFtp中定义续传方法            myFtp->conPut(m_File,_remoteFile);                                  //续传        }    }    else    {        delete m_File;        m_File = NULL;        qDebug() << tr("本地文件%1打开失败!").arg(_localFile);    }}//更新进度条void FtpManager::S_upDateProgress(qint64 _used, qint64 _total){    int tmpVal = _used / (double)_total * 100;    emit G_getProgressVal(tmpVal);}//ftp服务提示信息void FtpManager::S_commandFinish(int tmp, bool en){    Q_UNUSED(tmp);    if(myFtp->currentCommand() == QFtp::ConnectToHost){        if(en)            qDebug() << (tr("连接服务器出现错误:%1").arg(myFtp->errorString()));        else        {            qDebug() << (tr("连接到服务器成功"));            myFtp->login(m_userName,m_passwd);                           //登陆服务器        }    }    if (myFtp->currentCommand() == QFtp::Login){        if(en)            qDebug() << (tr("登录出现错误:%1").arg(myFtp->errorString()));        else            qDebug() << (tr("登录服务器成功"));    }    if (myFtp->currentCommand() == QFtp::Get)    {        if(en)        {            qDebug() << (tr("下载出现错误:%1").arg(myFtp->errorString()));        }        else        {            qDebug() << (tr("已经完成下载"));            m_File->flush();        }        m_File->close();        m_IsOpenFile = false;        delete m_File;        m_File = NULL;    }    else if(myFtp->currentCommand() == QFtp::Put)    {        if(en)        {            qDebug() << (tr("上传出现错误:%1").arg(myFtp->errorString()));        }        else        {            qDebug() << (tr("已经完成文件上传"));        }        m_File->close();        m_IsOpenFile = false;        delete m_File;        m_File = NULL;    }    else if (myFtp->currentCommand() == QFtp::Close)    {        qDebug() << (tr("已经关闭连接"));        if(m_IsOpenFile)        {            m_File->close();            delete m_File;            m_File = NULL;        }    }}


 

//-----------------------------------------------------------------测试用的小例子(懒得写了)

 

#include "mainwindow.h"#include "ui_mainwindow.h"MainWindow::MainWindow(QWidget *parent) :    QMainWindow(parent),    ui(new Ui::MainWindow){    ui->setupUi(this);    manager = new FtpManager("192.168.136.144","zhj","123456",21,this);    manager2 = new FtpManager("192.168.136.144","zhj","123456",21,this);    connect(manager,SIGNAL(G_getProgressVal(int)),SLOT(S_updateProgess(int)));    connect(manager2,SIGNAL(G_getProgressVal(int)),SLOT(S_updateProgess2(int)));}MainWindow::~MainWindow(){    delete ui;}//更新进度条void MainWindow::S_updateProgess(int _val){    ui->progressBar->setValue(_val);}//更新进度条void MainWindow::S_updateProgess2(int _val){    ui->progressBar_2->setValue(_val);}//普通下载void MainWindow::on_downloadBn_clicked(){    manager->S_dloadFile("VisualStdio.Net2005_En.iso","G:/VisualStdio.Net2005_En.iso");}//普通上传void MainWindow::on_uploadBn_clicked(){    manager->S_uloadFile("D:/QTWorkspace.zip","QTWorkspace.zip");}//下载(续传)void MainWindow::on_downloadBn_2_clicked(){    manager2->S_dloadFile("VisualStdio.Net2005_En.iso","G:/VisualStdio.Net2005_En.iso",true);}//停止void MainWindow::on_abort_clicked(){    manager2->S_abort();}//上传(续传)void MainWindow::on_abort_2_clicked(){    manager2->S_uloadFile("D:/QTWorkspace.zip","QTWorkspace.zip",true);}//停止void MainWindow::on_abort_3_clicked(){    manager->S_abort();}


 

//-----------------------------------效果

//普通文件上传

 

//普通文件下载

 

 

 

QFtp具有文件上传以及下载功能,

但是对于文件的续传支持上不好,因此 我使用Qt5.2.1编译器,从网络上下载了QFtp的实现,对其进行修改。目前为止,可以实现文件的续传功能。

 

7 1