为QFtp类添加断点下载的功能

我用的是QFtp For Qt5的独立版本。

先说FTP断点下载的原理:

第一,最重要的一点,断点续传需要服务器的支持,这个是必要条件。
传统的FTP SERVER是不支持断点续传的,因为它不支持REST指令,传统的FTP指令(我是指服务器端指令)并不包括REST指令。

第二,客户端要知道使用REST等一系列指令来作断点续传。

看看断点续传的详细过程(FTP SERVER):
首先客户端使用REST指令来告诉FTP SERVER它需要从文件的某个点开始传,接着用STOR或者RETR命令开始传文件,大概的命令的流程如下:

TYPE I
200 Type set to I.
PASV
227 Entering Passive Mode (204,48,18,69,98,250)
REST 187392
350 Restarting at 187392. Send STORE or RETRIEVE to initiate transfer.
RETR /pub/audio/pci/maestro-3/win2k/1056.zip
150 Opening BINARY mode data connection for /pub/audio/pci/maestro-3/win2k/1056.zip (936098 bytes).

首先使用TYPE命令告诉FTP SERVER使用BINARY模式传送文件;
然后使用PASV命令告诉FTP SERVER使用被动打开模式来传送文件;
接着使用REST 187392指令告诉FTP SERVER要从文件的187392字节开始传送;
最后使用RETR指令来传送文件。

从上面可以看出,这个FTP SERVER支持REST指令,有的FTP SERVER(特别的老的)是不支持这个指令的,这时即使FTP CLIENT支持断点续传也一点用都没有!

支持断点的FTP SERVER:Serv-U FTP,还有一系列的新出现的FTP SERVER;
不支持断点的:IIS4以前版本所带的都不行,IIS5 有,不家可以测试一下,登录进FTP SERVER,然后输入REST 1000命令,看服务器是否认识,认识就是支持断点。

现在最新的ftp服务器软件应该几乎都支持的、、

下面说下改动:

QFtp类里是get函数实现的下载,get原型是: int get(const QString &file, QIODevice *dev=0, TransferType type = Binary);

file是你要下载的文件名,Dev是你要保存的文件,可以不写的,那样默认是缓存到内存的,可以通过readAll()函数获取下载的内容的、、

TransferType传输模式,默认是二进制、、

为了实现断点,我们要用REST告诉服务器我们要从哪儿开始下载,这需要对这个函数动下手脚,你可以新建一个重载,我为了省事直接添加了哥默认值:我更改后原型:int get(const QString &file, QIODevice *dev=0, qulonglong size = 0, TransferType type = Binary);

添加一个size参数,无符号长整型的、、并默认值为0,接着就需要在函数主体里实现了、、照的get函数的实现:

先贴上全部的实现:

 

int QFtp::get(const QString &file, QIODevice *dev, qulonglong size, TransferType type)
{
    QStringList cmds;
    if (type == Binary)
        cmds << QLatin1String("TYPE Irn");
    else
        cmds << QLatin1String("TYPE Arn");
    cmds << QLatin1String("SIZE ") + file + QLatin1String("rn");
    cmds << QLatin1String(d->transferMode == Passive ? "PASVrn" : "PORTrn");
    if (size > 0)
    {
        cmds << QLatin1String("REST ") + QString::number(size) + QLatin1String("rn");//添加REST命令
    }
    cmds << QLatin1String("RETR ") + file + QLatin1String("rn");     return d->addCommand(new QFtpCommand(Get, cmds, dev));
}

其中:

 if (size > 0)
    {
        cmds << QLatin1String("REST ") + QString::number(size) + QLatin1String("rn");//添加REST命令
    }

是我添加的,逻辑很简单,当size设置为0的时候,不断点下载,大于0就启用断点下载、、不启用就设置为0就行了、、

还有查询某个文件大小,原来准备加个函数实现,最后发现QFtp类允许运行自己的命令就没加,因为ftp查询文件大小用SIZE命令,但是原来有ftp服务器不支持、、

用rawCommand("SIZE 文件名")函数得到文件大小

我的例子:https://github.com/dushibaiyu/DsbyLiteExample/tree/master/QFtpSeriesDown

《为QFtp类添加断点下载的功能》有3个想法

  1. 您好,我也想重构Qftp,但编译的时候报信号为保护变量,如下,请问你有没有遇到此情况,又该怎么解决?期待您的指点, 我用的是VS2008+QT4.8.41>qftp.cpp1>.qftp.cpp(2210) : error C2248: 'QFtp::commandStarted' : cannot access protected member declared in class 'QFtp'1> c:usersuserdesktopdsbyliteexample-masterqftpseriesdownqftp.h(144) : see declaration of 'QFtp::commandStarted'1> c:usersuserdesktopdsbyliteexample-masterqftpseriesdownqftp.h(53) : see declaration of 'QFtp'1>.qftp.cpp(2267) : error C2248: 'QFtp::stateChanged' : cannot access protected member declared in class 'QFtp'1> c:usersuserdesktopdsbyliteexample-masterqftpseriesdownqftp.h(138) : see declaration of 'QFtp::stateChanged'1> c:usersuserdesktopdsbyliteexample-masterqftpseriesdownqftp.h(53) : see declaration of 'QFtp'1>.qftp.cpp(2291) : error C2248: 'QFtp::commandFinished' : cannot access protected member declared in class 'QFtp'1> c:usersuserdesktopdsbyliteexample-masterqftpseriesdownqftp.h(145) : see declaration of 'QFtp::commandFinished'1> c:usersuserdesktopdsbyliteexample-masterqftpseriesdownqftp.h(53) : see declaration of 'QFtp'1>.qftp.cpp(2297) : error C2248: 'QFtp::done' : cannot access protected member declared in class 'QFtp'1> c:usersuserdesktopdsbyliteexample-masterqftpseriesdownqftp.h(146) : see declaration of 'QFtp::done'1> c:usersuserdesktopdsbyliteexample-masterqftpseriesdownqftp.h(53) : see declaration of 'QFtp'1>.qftp.cpp(2369) : error C2248: 'QFtp::commandFinished' : cannot access protected member declared in class 'QFtp'1> c:usersuserdesktopdsbyliteexample-masterqftpseriesdownqftp.h(145) : see declaration of 'QFtp::commandFinished'1> c:usersuserdesktopdsbyliteexample-masterqftpseriesdownqftp.h(53) : see declaration of 'QFtp'1>.qftp.cpp(2374) : error C2248: 'QFtp::done' : cannot access protected member declared in class 'QFtp'1> c:usersuserdesktopdsbyliteexample-masterqftpseriesdownqftp.h(146) : see declaration of 'QFtp::done'1> c:usersuserdesktopdsbyliteexample-masterqftpseriesdownqftp.h(53) : see declaration of 'QFtp'1>.qftp.cpp(2384) : error C2248: 'QFtp::stateChanged' : cannot access protected member declared in class 'QFtp'1> c:usersuserdesktopdsbyliteexample-masterqftpseriesdownqftp.h(138) : see declaration of 'QFtp::stateChanged'1> c:usersuserdesktopdsbyliteexample-masterqftpseriesdownqftp.h(53) : see declaration of 'QFtp'1>.qftp.cpp(2397) : error C2248: 'QFtp::rawCommandReply' : cannot access protected member declared in class 'QFtp'1> c:usersuserdesktopdsbyliteexample-masterqftpseriesdownqftp.h(142) : see declaration of 'QFtp::rawCommandReply'1> c:usersuserdesktopdsbyliteexample-masterqftpseriesdownqftp.h(53) : see declaration of 'QFtp'1>mainwindow.cpp1>.mainwindow.cpp(14) : error C2065: 'nullptr' : undeclared identifier1>.mainwindow.cpp(15) : error C2248: 'QFtp::rawCommandReply' : cannot access protected member declared in class 'QFtp'1> c:usersuserdesktopdsbyliteexample-masterqftpseriesdownqftp.h(142) : see declaration of 'QFtp::rawCommandReply'1> c:usersuserdesktopdsbyliteexample-masterqftpseriesdownqftp.h(53) : see declaration of 'QFtp'1>.mainwindow.cpp(15) : error C2059: syntax error : '['1>.mainwindow.cpp(15) : error C2143: syntax error : missing ')' before '{'1>.mainwindow.cpp(15) : error C2143: syntax error : missing ';' before '{'1>.mainwindow.cpp(16) : error C2065: 'str' : undeclared identifier1>.mainwindow.cpp(17) : error C2059: syntax error : ')'1>.mainwindow.cpp(18) : error C2248: 'QFtp::readyRead' : cannot access protected member declared in class 'QFtp'1> c:usersuserdesktopdsbyliteexample-masterqftpseriesdownqftp.h(140) : see declaration of 'QFtp::readyRead'1> c:usersuserdesktopdsbyliteexample-masterqftpseriesdownqftp.h(53) : see declaration of 'QFtp'1>.mainwindow.cpp(18) : error C2059: syntax error : '['1>.mainwindow.cpp(18) : error C2143: syntax error : missing ')' before '{'1>.mainwindow.cpp(18) : error C2143: syntax error : missing ';' before '{'1>.mainwindow.cpp(20) : error C2059: syntax error : ')'1>main.cpp1>ftpcutdown.cpp1>.ftpcutdown.cpp(36) : error C2248: 'QNetworkReply::finished' : cannot access protected member declared in class 'QNetworkReply'1> c:qt4.8.4includeqtnetwork../../src/network/access/qnetworkreply.h(149) : see declaration of 'QNetworkReply::finished'1> c:qt4.8.4includeqtnetwork../../src/network/access/qnetworkreply.h(65) : see declaration of 'QNetworkReply'1>.ftpcutdown.cpp(36) : error C2059: syntax error : '['1>.ftpcutdown.cpp(36) : error C2143: syntax error : missing ')' before '{'1>.ftpcutdown.cpp(36) : error C2143: syntax error : missing ';' before '{'1>.ftpcutdown.cpp(39) : error C2059: syntax error : ')'1>Generating Code...

    1. C2059和C2143错误是因为我用的C++11的labdma表达式,Vs2008通不过的,至少需要VS2012/gcc4.7,另外我是基于Qt5的,用的也是Qt5新加的信号槽语法,错误很正常。ftpcutdown.cpp这个文件是测试Qnetworkmanager下载的,这个用的是http的原理,断点失败的。qftp.cpp这个文件我是从别处找来的,也是基于qt5的、、Qt4好像本身就有个qftp类,我是直接上手的Qt5、、这个文件我用4.8.5测试,编译是的确不过的、、、Qt5.x + gcc4.7+/VS2012+ 才会编译没错误、、、Qt4重构QFtp的话,这个我也没用过qt4的,好像出不了什么力、、、

发表评论

电子邮件地址不会被公开。 必填项已用*标注