FTP断点续传的原理Word文件下载.docx
《FTP断点续传的原理Word文件下载.docx》由会员分享,可在线阅读,更多相关《FTP断点续传的原理Word文件下载.docx(13页珍藏版)》请在冰点文库上搜索。
![FTP断点续传的原理Word文件下载.docx](https://file1.bingdoc.com/fileroot1/2023-4/30/49e5e395-7dd3-422e-9d89-3aef0c67372d/49e5e395-7dd3-422e-9d89-3aef0c67372d1.gif)
FTP和HTTP断点续传的道理
第一,最重要的一点,断点续传需要服务器的支持,这个是必要条件。
传统的FTPSERVER是不支持断点续传的,因为它不支持REST指令,传统的FTP指令(我是指服务器端指令)并不包括REST指令。
第二,客户端要知道使用REST等一系列指令来作断点续传。
看看断点续传的详细过程(FTPSERVER):
首先客户端使用REST指令来告诉FTPSERVER它需要从文件的某个点开始传,接着用STOR或者RETR命令开始传文件,大概的命令的流程如下:
TYPEI
200TypesettoI.
PASV
227EnteringPassiveMode(204,48,18,69,98,250)
REST187392
350Restartingat187392.SendSTOREorRETRIEVEtoinitiatetransfer.
RETR/pub/audio/pci/maestro-3/win2k/1056.zip
150OpeningBINARYmodedataconnectionfor/pub/audio/pci/maestro-3/win2k/1056.zip(936098bytes).
首先使用TYPE命令告诉FTPSERVER使用BINARY模式传送文件;
然后使用PASV命令告诉FTPSERVER使用被动打开模式来传送文件;
接着使用REST187392指令告诉FTPSERVER要从文件的187392字节开始传送;
最后使用RETR指令来传送文件。
从上面可以看出,这个FTPSERVER支持REST指令,有的FTPSERVER(特别的老的)是不支持这个指令的,这时即使FTPCLIENT支持断点续传也一点用都没有!
支持断点的FTPSERVER:
Serv-UFTP,还有一系列的新出现的FTPSERVER;
不支持断点的:
IIS4以前版本所带的都不行,IIS5有,不家可以测试一下,登录进FTPSERVER,然后输入REST1000命令,看服务器是否认识,认识就是支持断点。
上面说的是FTPSERVER的断点,HTTP的断点续传是这样的:
在以前版本的HTTPSERVER也是不支持断点的,HTTP/1.1开始就支持了,具体如下:
在HTTP请求的头部信息里面,通常是这样的:
GEThttp:
//xxx.xxx.xxx.xxx/index.htmlHTTP/1.1
Host:
Accept:
*/*
上面是HTTP请求头的主要内容,是浏览器等客户端发给HTTPSERVER的信息。
在这个请求头里面,第一行叫做RequestLine,GET叫做请求方法(通常得到一个HTML页面都是用GET,CGI等请求是用POST),buddy.org/index.html是URL,HTTP/1.1为版本号。
buddy.org是HTTP服务器名字,这也是HTTP/1.1的新东东,以前做虚拟主机可是要一个主机名对应多个IP,现在好了......呵呵,这个离题太远,不说了)
要做断点续传,浏览器等客户端需要在请求头里面发送
Range:
bytes=1140736-
这样的请求,就是告诉HTTPSERVER,这个文件要从1140736字节开始传送。
最后一点,大家看了上面的描述可能会有一个问题,那么多点传送怎么做呢?
那就是多起几个线程,连接到服务器,用断点指令来传送文件,在传送的过程中,会检查前面的(比如说第一个蚂蚁)得到的文件的部分是否超过了后面的(比如说第二个蚂蚁)的起点,相等就停前面的蚂蚁,最后再合并几个部分,就得到一个完整的文件了
介绍可以断点续传软件FTPEXPLORER
经过比较,觉得FTPExplorer还是不如CuteFTP来得方便,但它最大的优点是免费不用注册,所以也值得一试。
FTPEXPLORER的主要特点是:
(使用图解看这里)
1.支持断点续传:
当由于线路中断而导致下载的文件中断时,
FTPEXPLORER可以通过TRANSEERMANAGER
(传输管理器)帮助你在下次登录时从上次中断的地方继续下载文件,这将节省你大量的时间和通讯费
用。
传输管理器允许你迅速了解下载或上载文件的详细信息,如FTP位置、下载状态、下载的目的地
等。
当文件下载完毕,文件左边的标记变蓝;
当文件传输时因故中断,文件左边的标记为黄色;
当文件
传输地因故中断,文件左边的标记变红;
这时,只要在中断的文件名上单击鼠标右键,就可以看到一个
对话框,CANCEL表示取消文件传输,RESUBMIT表示进行断点续传。
2.类似
Windows95中的资源管理器,界面友好。
不同的是它显示的是远方FTP站点服务器的内容。
(见下图)
3.自动联接:
当联机请求被拒绝时(有的热门
FTP站点限制访问人数),FTPEXPLORER能够自动重新与暂
时拥挤的FTP站点建立联接,而且可以自由设定重新联接的次数(最多为99次)和时间间隔(如隔90秒
后进行重拨)。
一旦联机成功,FTPEXPLORER会自动提示用户。
4.FTPEXPLORER
全面支持拖放功能(DraganDrop),可以将文件拖到你指定的位置甚至桌面上并可以在桌
面上建立捷径。
(注这些功能另一个也支持断点续传功能的著名软件CUTEETP也有,
但CUTEETP的注册版本才具有断点续传功能)。
FTPEXPLORER网址:
ftp:
//或
ftp下载的好处我在这里就不多说了,许多工程会把ftp下载作为一个重要的功能来实现。
微软提供的WinInet类可以利用下面这些函数:
InternetOpen;
InternetConnect;
GetCurrentDirectory;
SetCurrentDirectory;
FtpGetFile;
很容易实现ftp的下载,网上关于这方面的文章也很多。
但是要实现ftp的多线程下载,利用这些函数就显得有些牵强了。
用socket根据ftp协议来开发将会变的十分灵活。
下面我就逐步的讲解整个开发的过程:
开发环境BCB(组件模式),VC环境下请自行稍作改动。
看了这篇文章后对于BCB开发人员来说,不仅可以对FlashGet等软件的开发原理有一定的了解,特别是在开发组件方面也有很大的指导作用,请耐心的将它看完。
很简单!
!
首先介绍一下部分ftp协议:
图一FTP服务示意图
用户FTP和服务器FTP之间要传送文件,需要有两个连接:
命令通道和数据连接,从名字上就可以看出命令通道是传送命令的,数据通道是用于传送文件。
服务器与服务器之间的数据传送在此就不多作解释。
主要用到的命令为:
USER,PASS,TYPE,SIZE,REST,CWD,PWD,RETR,PASV,PORT,QUIT;
USER:
参数是标记用户的Telnet串。
用户标记是访问服务器必须的,此命令通常是控制连接后第一个发出的命令,有些主机还会要求口令和帐户。
服务器可以在任何时间接收新的USER命令以改变访问控制和(或)帐户信息。
这可以重新开始登录过程,所以传输参数不变,在进行中的文件传输在过去的访问控制参数下完成。
PASS:
参数是标记用户口令的Telnet串。
此命令紧跟USER命令,在某些站点它是完成访问控制不可缺少的一步。
因此口令是个重要的东西,因此不能显示出来,服务器方没有办法隐藏口令,所以这一任务得由用户FTP进程完成。
TYPE:
参数指定表示类型。
有些类型需要第二个参数,第一个参数由单个Telnet字符定义,第二个参数是十进制整数指定字节大小,参数间以<
SP>
分隔。
下面是格式:
图二 TYPE参数示意图
默认表示类型是ASCII非打印字符,如果参数未改变,以后只改变了第一个参数,则使用默认值。
SIZE:
参数从FTP服务器上返回指定文件的大小。
REST:
参数域代表服务器要重新开始的那一点,此命令并不传送文件,而是略过指定点后的数据,此命令后应该跟其它要求文件传输的FTP命令。
CWD:
此命令使用户可以在不同的目录或数据集下工作而不用改变它的登录或帐户信息。
传输参数也不变。
参数一般是目录名或与系统相关的文件集合。
PWD:
改变当前的工作目录。
RETR:
开始传送指定的文件。
(从REST参数指定的偏移量开始传送)
PASV:
此命令要求服务器DTP在指定的数据端口侦听,进入被动接收请求的状态,参数是主机和端口地址。
PORT:
参数是要使用的数据连接端口,通常情况下对此不需要命令响应。
如果使用此命令时,要发送32位的IP地址和16位的TCP端口号。
上面的信息以8位为一组,逗号间隔十进制传输。
QUIT:
退出登录。
各个参数的具体用法举例如下:
USERsandy\r\n//用户名为sandy登录
PASSsandy\r\n//密码为sandy
TYPEI\r\n
SIZEsandy.txt\r\n//如果sandy.txt文件存在,则返回该文件的大小
REST100\r\n//重新指定文件传送的偏移
CWDinfor/\r\n//获取当前的工作目录
PWDtemp/\r\n//改变当前的工作目录
RETR\r\n//开始传送文件
PASV\r\n//进入被动模式
PORTh1,h2,h3,h4,p1,p2\r\n//进入主动模式,h1,h2,h3,h4为ip地址的4个部分。
p1,p2是16进制的端口号
下面介绍一下各个函数的使用顺序和一些应注意的地方:
使用这些命令的前提条件是客户端和服务器端建立了连接。
比如ftp服务器地址:
192.168.1.81,端口:
21。
那么利用Winsock的API函数建立socket连接,然后使用USER,PASS登陆FTP服务器.需要下载文件,要确保文件必须在当前工作目录下,可以使用命令CWD和PWD。
查看和更改当前的工作目录。
使用SIZE命令获取文件的大小。
我们想要多线程下载那么就要求服务器支持该功能。
一般我们都会在开头先使用REST命令判断该ftp站点是否支持多线程下载。
PORT和PASV两个命令是用来建立数据连接的。
他们的主要区别是:
PORT需要你指定一个ip地址和端口与服务器建立连接。
PASV命令服务器会返回h1,h2,h3,h4,p1,p2样式的数据供客户端连接。
等数据连接建立后,就可以了使用REST,RETR进行多线程和断点续传文件下载了。
上面讲解了一点ftp下载的基本知识,下面主要介绍的是断点续传的文件保存技巧。
若要讲断点续传的文件保存方式至少可以说出10种,但是各种方法都有利有弊,下面主要介绍一种我在工作中常常使用的一种文件保存方式:
比如要下载一个364544字节的文件,文件名为:
namelock.avi。
因为要断点续传,所以在下载的过程中必须得保存文件的大小,已经下载的文件的大小和各个线程的任务。
有两种方法:
一、可以产生两个文件:
内容文件和配置文件。
二、只需一个文件:
把配置文件的数据加载到内容文件的末尾。
这两个都不失为好方法。
我使用的是前一种,因为我水平有限,(对于临界资源的访问总是不能做到互坼,老出问题。
)。
这里的后缀名希望大家要把它放在心上,后缀名是个象征性的东西。
就拿我们公司来说,拥有自己的MPEG编码、解码技术,比如原来5m的一首mp3歌曲,通过编码可以转换成500K左右的.fun文件(funinhand的前三个字)。
再利用我们自己的解码播放器边下载边解码边播放,音质和mp3不相上下。
真正实现了手机上的流媒体技术。
受到国内外高科技大公司的信赖。
(不好意思,这里有点像做广告了。
)讲这些的另外一个企图是这样的:
内容文件所使用的后缀名是我女朋友的英文名(namelock)的前三个字母.nam。
配置文件使用的是我自己的英文名(sandy)的前三个字母.san。
所以说写程序也可以很浪漫,因为这,女朋友又给了我的月生活零用钱增加了几元,哈哈(大家也可以效仿)。
言归正传,这两个文件严格意义上来讲是临时文件,当文件下载完毕的时候,namelock.avi.nam内容文件应该改名为:
namelock.avi.san配置文件也应该及时的删除。
FTP多线程下载技术部分:
前面我介绍了文件的保存技巧,主要也是为了多线程服务。
现在有个namelock.avi文件需要下载。
文件的大小为:
364544字节。
要用8个下载线程。
第一步:
将namelock.avi文件分成8个子模块。
这里要注意的地方是我所说的分成8个字模块,并不是把文件的内容分别存放到8个不同的缓冲区里。
而是生成8个不同的文件偏移量。
很多时候程序员为了偷懒往往容易一次性讲文件读入内存,这样带来的后果是不堪设想的。
一个比较理想的方法是这样的。
boolDealFile(stringfileName)//随便写个函数说明
{
FILE*file;
DWORDfileSize,pos;
intreadLen;
//MAX_BUFFER_LEN在头文件里定义,这里能够保证数据不丢失,也不至于内存逸出
char*buffer=newchar[MAX_BUFFER_LEN];
file=fopen(fileName.c_str(),"
r+b"
);
if(file==NULL)returnfalse;
fseek(file,0,2);
fileSize=ftell(file);
//取得文件的大小
fseek(file,0,0);
do{
readLen=fread(buffer,sizeof(char),MAX_BUFFER_LEN,file);
if(readLen>
0)
pos+=readLen;
//对读取的文件做处理
}
}while(pos<
fileSize);
//循环读取文件
delete[]buffer;
fclose(file);
//释放资源
returntrue;
8个线程下载文件时,都要对内容文件和配置文件进行读写。
这样如果没有处理好,很有可能会造成访问文件失败,我定义了一个全局变量FileLocked,如果FileLocked=true说明文件正在被某个线程访问。
所以使用Sleep(10)睡眠等待。
当某个线程进入读写文件时必须设置FileLocked=true;
访问文件完毕必须将FileLocked=false;
这样就能很好的控制各个线程对文件的访问了。
(对临界资源的访问有API提供了很多很好的解决方法,请查阅)。
8个下载线程同时下载文件时,完成部分下载是随机的。
那么怎么样把随机的文件数据按照偏移量正确的写入文件呢?
我是这样实现的,当要下载文件namelock.avi时,首先查找文件namelock.avi.san配置文件是否存在。
如果存在,说明上次已经下载过部分该文件,就可以断点续传了。
如果没有找到该文件,那么生成和该文件的大小一样大的文件,文件里所有的数据都为0,(可以使用函数memset(buffer,10000,'
'
0'
))和一个配置文件。
然后利用fseek函数将数据正确的覆盖原先的0;
接下来要介绍一写配置文件的格式了。
很简单,配置文件的内容主要包括:
文件在本地保存的绝对路径、文件的大小、线程的个数、已经下载的文件大小,各个线程的任务(在原始文件起始位置和结束位置,中间使用'
-'
分开);
如:
D:
\mm\namelock.avi//文件保存在这里
364544//文件大小
5//有5个线程在下载
0//已经下载了0字节
0-72908//线程1的下载任务
72908-145816//线程2的下载任务
145816-218724//线程3的下载任务
218724-291632//线程4的下载任务
291632-364544//线程5的下载任务
以上是开始下载时的各个线程的任务分配。
\mm\namelock.avi
364544
5
113868
72908-72908
113868-145816
145816-218724
218724-291632
291632-364544
以上是某一时刻各个线程的任务分配情况。
各个线程任务分配是这样实现的。
在开始下载时,文件平均分成若干块进行下载。
如第一个线程一开始的任务是从文件的0位置开始下载一直到72908位置处。
线程1每次下载一块数据后就要调整任务,如第一次下载了20800字节的数据,那么线程1的任务将改为:
20800-72908。
如此下去,直到任务为72908-72908时表示线程1完成了当前的下载任务。
此时,线程1就分析各个线程的任务,找出任务最为繁忙的一个线程:
如线程3:
14816-218724。
那么线程1就自动去调整任务,拿50%的任务来再次下载。
周而复始直到各个线程都完成任务。
不过这里有一点需要注意:
为了避免重复下载部分数据,在调整任务的时候,起始的文件便移量必须加上接受缓冲器的字节数,因为如前面所举的列子来看。
线程1和线程3在平衡负载的时候,线程正在下载数据,如果所剩的数据比接受缓冲器的大小还小,线程1和线程3的部分下载数据将会重复。
在调整任务和分析任务的时候,会发现一个问题。
就是读取文件数据太过频繁。
于是我用了一个数据结构。
在下载文件的过程中始终打开配置文件,这样速度提高了很多。
在文件下载完毕后关闭文件。
数据结构如下:
typedefstructFromToImpl{
DWORDfrom;
//任务起始位置
DWORDto;
//任务结束位置
}m_fromTo;
typedefstructInfroImpl{
StringfileLoad;
//文件保存位置
DWORDfileSize;
//文件大小
intthreadCnt;
//下载线程数
DWORDalreadyDownloadCnt;
//已经下载的文件大小
FromToImpl*fromToImpl;
//各个线程的任务描述
}m_inforImpl;
具体实现的细节,请查看源程序。