本文共 5915 字,大约阅读时间需要 19 分钟。
断点续传的原理
其实断点续传的原理很简单,就是在Http的请求上和一般的下载有所不同而已。
打个比方,浏览器请求服务器上的一个文时,所发出的请求如下:
假设服务器域名为wwww.sjtu.edu.cn,文件名为down.zip。
GET /down.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 2001 12:56:11 GMT
ETag=W/"02ca57e173c11:95b"
Content-Type=application/octet-stream
Server=Microsoft-IIS/5.0
Last-Modified=Mon, 30 Apr 2001 12:56:11 GMT
所谓断点续传,也就是要从文件已经下载的地方开始继续下载。所以在客户端浏览器传给 Web服务器的时候要多加一条信息--从哪里开始。
下面是用自己编的一个"浏览器"来传递请求信息给Web服务器,要求从2000070字节开始。
GET /down.zip HTTP/1.0
User-Agent: NetFox
RANGE: bytes=2000070-
Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2
仔细看一下就会发现多了一行RANGE: bytes=2000070-
这一行的意思就是告诉服务器down.zip这个文件从2000070字节开始传,前面的字节不用传了。
服务器收到这个请求以后,返回的信息如下:
206
Content-Length=106786028
Content-Range=bytes 2000070-106786027/106786028
Date=Mon, 30 Apr 2001 12:55:20 GMT
ETag=W/"02ca57e173c11:95b"
Content-Type=application/octet-stream
Server=Microsoft-IIS/5.0
Last-Modified=Mon, 30 Apr 2001 12:55:20 GMT
和前面服务器返回的信息比较一下,就会发现增加了一行:
Content-Range=bytes 2000070-106786027/106786028
返回的代码也改为206了,而不再是200了。
服务端代码:
- <%
-
-
-
-
-
-
-
-
-
-
-
- String s = "I://SetupRes//Sun//j2re-1_4_2_05-windows-i586-p.exe";
-
-
-
-
-
- java.io.File f = new java.io.File(s);
- java.io.FileInputStream fis = new java.io.FileInputStream(f);
-
- response.reset();
-
- response.setHeader("Server", "playyuer@Microshaoft.com");
-
-
-
-
- response.setHeader("Accept-Ranges", "bytes");
-
- long p = 0;
- long l = 0;
-
- l = f.length();
-
-
-
-
-
- if (request.getHeader("Range") != null)
- {
-
-
-
-
- response.setStatus(javax.servlet.http.HttpServletResponse.SC_PARTIAL_CONTENT);
-
-
-
-
- p = Long.parseLong(request.getHeader("Range").replaceAll("bytes=","").replaceAll("-",""));
- }
-
-
-
-
- response.setHeader("Content-Length", new Long(l - p).toString());
-
- if (p != 0)
- {
-
-
-
- response.setHeader("Content-Range","bytes " + new Long(p).toString() + "-" + new Long(l -1).toString() + "/" + new Long(l).toString());
- }
-
-
-
-
-
-
- response.setContentType("application/octet-stream");
-
-
-
-
-
- response.setHeader("Content-Disposition", "attachment;filename=/"" + f.getName() + "/"");
-
-
- fis.skip(p);
-
- byte[] b = new byte[1024];
- int i;
-
-
-
- while ( (i = fis.read(b)) != -1 )
- {
- response.getOutputStream().write(b,0,i);
- }
-
- fis.close();
- %>
客户端测试代码:
- public static void down(String URL,long nPos,String savePathAndFile){
- HttpURLConnection conn =null;
- try{
-
-
-
-
-
-
-
-
-
- conn = (HttpURLConnection)new URL(URL).openConnection();
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- InputStream input = conn.getInputStream();
- RandomAccessFile oSavedFile = new RandomAccessFile(savePathAndFile,
- "rw");
-
- oSavedFile.seek(nPos);
- byte[] b = new byte[1024];
- int nRead;
-
- while ((nRead = input.read(b, 0, 1024)) > 0) {
- (oSavedFile).write(b, 0, nRead);
- }
- conn.disconnect();
- } catch (MalformedURLException e) {
- e.printStackTrace();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- public static void main(String[] args) {
- String url = "http://localhost:8181/ssoapp/clientRequest";
- String savePath = "e://";
- String fileName = "4.ppt";
- String fileNam = fileName;
- HttpURLConnection conn = null;
- try {
-
- } catch (Exception e) {
- e.printStackTrace();
- }
- File file = new File(savePath + fileName);
-
- int i = 0;
- if (file.exists()) {
-
- long localFileSize = file.length();
- System.out.println("已有文件大小为:" + localFileSize);
-
- if (localFileSize >0) {
- System.out.println("文件续传");
- down(url, localFileSize, savePath + fileName);
- } else {
- System.out.println("文件存在,重新下载");
- down(url, 0, savePath + fileName);
- }
- } else {
- try {
- file.createNewFile();
- System.out.println("下载中");
- down(url, 0, savePath + fileName);
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- }