【游客模式】——注册会员,加入11RIA 闪客社区吧!一起见证Flash的再次辉煌……
您需要 登录 才可以下载或查看,没有帐号?立即注册
x
转载:QQ群
地址:未知
作者:未知
一、Http断点续传原理
现在基本上任何一个下载工具都是支持断点续传的,抛开P2P的成分不谈,我们单说通过HTTP服务器是如何实现断点续传的。关键在于你向HTTP服务器发起文件请求的时候,是否明确的告知,要下载文件的哪个区域,我们都知道HTTP请求是有一个Header的,实际上里面有个属性是定义下载的区域的,这个属性就是Range,它接收的值是一个区间范围,比如:Range:bytes=0-10000
这样我们就可以按照一定的规则,将一个大文件拆分为若干很小的部分,然后分批次的下载,每个小块下载完成之后,都合并到文件中,这样即时中间中断了下载,我们重新开始下载的时候,也可以通过文件的字节长度来判断下载的起始点,然后重启断点续传的过程,直到最后完成下载过程。
1、 下面是非断点续传的Http剖析
假设我们通过浏览器去下载一个
称为hello.zip的文件。那么浏览器发出的请求信息如下:
GET /hello.zip HTTP/1.1
Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/vnd.ms-excel, application/msword, application/vnd.ms-powerpoint
Accept-Language: zh-cn
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0)
Connection: Keep-Alive
服务器收到请求后,按要求寻找请求的文件,提取文件的信息,然后返回给浏览器,返回信息如下:
200
Content-Length=106786028
Accept-Ranges=bytes
Date=Mon, 30 Apr 2009 12:56:11 GMT
ETag=W/"02ca57e173c12:95b"
Content-Type=application/octet-stream
Last-Modified=Mon, 30 Apr 2009 12:56:11 GMT
2、下面是断点续传的http剖析
如果自己编的一个客户端程序来传递请求信息给Web服务器,要求从1000070字节开始。
GET /hello.zip HTTP/1.0
User-Agent: NetFox
RANGE: bytes=1000070-
Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2
仔细看一下就会发现多了一行RANGE: bytes=1000070-,这一行的意思就是告诉服务器hello.zip这个文件从1000070字节开始传,前面的字节不用传了。
服务器收到这个请求以后,返回的信息如下:
206
Content-Length=106786028
Content-Range=bytes 1000070-106786027/106786028
Date=Mon, 30 Apr 2009 12:55:20 GMT
ETag=W/"02ca57e173c12:95b"
Content-Type=application/octet-stream
Last-Modified=Mon, 30 Apr 2009 12:55:20 GMT
和前面服务器返回的信息比较一下,就会发现增加了Content-Range一行,且返回的代码也改为206了,而不再是200了。
以上就是HTTP断点续传的原理,具体通过什么技术实现,比如Java、C++、Flex等,都可以实现。
二、Flex实现的文件下载断点续传
下面是基于AS3+Flash Player+AIR,制作一个断点续传的小程序,大概实现思路如下:
1、首先对文件发起请求,得到文件的尺寸(字节长度),但并不下载
2、然后将文件划分为若干区域,对第一个区域的内容发起请求(通过指定HTTP头的Range)
3、第一个区域的内容很快下载完成,使用File保存到本地文件
4、移动指针,对第二个区域的内容发起请求,下载完毕后与文件合并
5、以此类推,直到下载完成整个文件
以下是实现代码:
[Actionscript3] 纯文本查看 复制代码 <?xml version="1.0" encoding="utf-8"?>
<mx:WindowedApplication xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" title="梦想下载" >
<mx:Script>
<![CDATA[
import flash.net.URLLoader;
import flash.net.URLStream;
import flash.net.URLRequest;
import flash.utils.ByteArray;
import mx.controls.Alert;
private var contentLength:int = 0;
private var file:File;
private var startPoint:int = 0;
private var endPoint:int = 0;
private var rangeStream:URLStream;
private var isInit:Boolean = false;
private var range:int = 1024000; //每次下载的字节数,
private var currentData:ByteArray;
private var progress:Number = 0;
private function init():void {
var dotSplitLength:uint = videoURL.text.split("/").length;//这两行代码是为了获取下载文件的名称
var fileName:String = videoURL.text.split("/")[dotSplitLength-1];
file = new File("C:/DownLoadTemp/"+fileName);//创建一个和下载文件名称一致的文件,保存在D盘temp目录下
isInit = true;
}
private function doDownload():void {//先发送一个下载请求,可以得到文件的真实尺寸
var getContentLengthRequest:URLRequest = new URLRequest(videoURL.text);
var getContentLengthLoader:URLLoader = new URLLoader();
getContentLengthLoader.addEventListener(ProgressEvent.PROGRESS ,function(e:ProgressEvent):void {
contentLength = getContentLengthLoader.bytesTotal;//得到文件的真实尺寸
getContentLengthLoader.close();//停止下载
downloadByRange();//按照断点续传的方式下载
});
getContentLengthLoader.load(getContentLengthRequest);
}
private function downloadByRange():void {//按照断点续传的方式下载
if(!isInit)
init();
var fileStr:FileStream = new FileStream();
if(file.exists) {//如果文件是存在的,就说明下载过,需要计算从哪个点开始下载
fileStr.open(file, FileMode.READ);
startPoint = fileStr.bytesAvailable;//计算从哪个点开始下载
fileStr.close();//关闭文件流
}
endPoint = startPoint+range>contentLength?contentLength:startPoint+range;
if(startPoint==contentLength)
{
Alert.show("您已经完成了下载");
return;
}
var rangeRequest:URLRequest = new URLRequest(videoURL.text);
var header:URLRequestHeader = new URLRequestHeader("Range", "bytes="+startPoint+"-"+endPoint);//注意这里很关键,我们在请求的Header里包含对Range的描述,这样服务器会返回文件的某个部分
rangeRequest.requestHeaders.push(header);//将头信息添加到请求里
rangeStream = new URLStream();
rangeStream.addEventListener(Event.COMPLETE ,function(e:Event):void {
var bytesLength:int = rangeStream.bytesAvailable;
currentData = new ByteArray();
rangeStream.readBytes(currentData, 0, bytesLength); //得到下载的数据
fileStr = new FileStream();
fileStr.open(file, FileMode.UPDATE);
fileStr.position = fileStr.bytesAvailable;//将指针指向文件尾
fileStr.writeBytes(currentData, 0, currentData.length);//在文件中写入新下载的数据
fileStr.close();//关闭文件流
progress = endPoint/contentLength * 100;//计算下载进程
bar.setProgress(progress,100);
bar.label= "Progress" + " " + progress + "%";
if(endPoint < contentLength) {
downloadByRange();//如果下载没有完成,则执行下一个断点下载,直到下载完毕整个文件
}
});
rangeStream.load(rangeRequest);//发起请求
}
private function pause():void {//暂停下载
if(rangeStream!=null&&rangeStream.connected)
rangeStream.close();
}
]]>
</mx:Script>
<mx:Canvas width="494" height="284" horizontalCenter="0" verticalCenter="0">
<mx:Label x="21" y="87" text="下载地址" width="53" fontSize="12" />
<mx:TextInput x="82" y="87" width="399" id="videoURL" text="http://192.168.12.131:8080/FlexChatServer/AContreCourant.avi"/>
<mx:Button x="160" y="141" label="下载" id="btDownload" fontSize="12" click="doDownload();btDownload.enabled=false;btPause.enabled=true;btContinue.enabled=false"/>
<mx:Button x="221" y="141" label="暂停" id="btPause" fontSize="12" enabled="false" click="pause();btPause.enabled=false;btContinue.enabled=true"/>
<mx:Button x="281" y="141" label="继续" id="btContinue" fontSize="12" enabled="false" click="downloadByRange();btPause.enabled=true;btContinue.enabled=false"/>
<mx:ProgressBar x="82" y="194" width="399" id="bar" labelPlacement="bottom" themeColor="#EE1122" minimum="0" visible="true" maximum="100"
color="0x323232" label="Progress 0%" direction="right" mode="manual" />
</mx:Canvas>
</mx:WindowedApplication>
运行效果:
|