技术总结_断点续传

今天看到一篇关于Android的断点续传实例的文章,正好自己要学习这一方面的知识,就好好学习了一下。作者写的很好。但对其中的一些代码不太了解,比如HttpURLConnection的setRequestProperty()方法不太了解。后来上百度Google了一下,终于找到了答案。最终原因是自己对于Http协议方面的知识不太了解,知道了客户端和服务器端交互的方式,及过程原理,就自然明白了。找了一篇文章,例子是Java的,和android差不多。***************************************华丽的分割*******************************************(一)断点续传的原理 其实断点续传的原理很简单,就是在http的请求上和一般的下载有所不同而已。打个比方,浏览器请求服务器上的一个文时,所发出的请求如下:假设服务器域名为wwww.sjtu.edu.cn,文件名为down.zip。get /down.zip http/1.1accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/vnd.ms-excel, application/msword, application/vnd.ms-powerpoint, */*accept-language: zh-cnaccept-encoding: gzip, deflateuser-agent: mozilla/4.0 (compatible; msie 5.01; windows nt 5.0)connection: keep-alive服务器收到请求后,按要求寻找请求的文件,提取文件的信息,然后返回给浏览器,返回信息如下:200content-length=106786028accept-ranges=bytesdate=mon, 30 apr 2001 12:56:11 gmtetag=w/"02ca57e173c11:95b"content-type=application/octet-streamserver=microsoft-iis/5.0last-modified=mon, 30 apr 2001 12:56:11 gmt所谓断点续传,也就是要从文件已经下载的地方开始继续下载。所以在客户端浏览器传给web服务器的时候要多加一条信息--从哪里开始。下面是用自己编的一个"浏览器"来传递请求信息给web服务器,要求从2000070字节开始。get /down.zip http/1.0user-agent: netfoxrange: bytes=2000070-accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2仔细看一下就会发现多了一行range: bytes=2000070-这一行的意思就是告诉服务器down.zip这个文件从2000070字节开始传,前面的字节不用传了。服务器收到这个请求以后,返回的信息如下:206content-length=106786028content-range=bytes 2000070-106786027/106786028date=mon, 30 apr 2001 12:55:20 gmtetag=w/"02ca57e173c11:95b"content-type=application/octet-streamserver=microsoft-iis/5.0last-modified=mon, 30 apr 2001 12:55:20 gmt和前面服务器返回的信息比较一下,就会发现增加了一行:content-range=bytes 2000070-106786027/106786028返回的代码也改为206了,而不再是200了。知道了以上原理,就可以进行断点续传的编程了。(二)java实现断点续传的关键几点 (1)用什么方法实现提交range: bytes=2000070-。当然用最原始的socket是肯定能完成的,不过那样太费事了,其实java的net包中提供了这种功能。代码如下:url url = new url("http://www.sjtu.edu.cn/down.zip");httpurlconnection httpconnection = (httpurlconnection)url.openconnection();//设置user-agenthttpconnection.setrequestproperty("user-agent","netfox");//设置断点续传的开始位置httpconnection.setrequestproperty("range","bytes=2000070");//获得输入流inputstream input = httpconnection.getinputstream();从输入流中取出的字节流就是down.zip文件从2000070开始的字节流。大家看,其实断点续传用java实现起来还是很简单的吧。接下来要做的事就是怎么保存获得的流到文件中去了。保存文件采用的方法。我采用的是io包中的randaccessfile类。操作相当简单,假设从2000070处开始保存文件,代码如下:randomaccess osavedfile = new randomaccessfile("down.zip","rw");long npos = 2000070;//定位文件指针到npos位置osavedfile.seek(npos);byte[] b = new byte[1024];int nread;//从输入流中读入字节流,然后写到文件中while((nread=input.read(b,0,1024)) > 0){osavedfile.write(b,0,nread);}怎么样,也很简单吧。接下来要做的就是整合成一个完整的程序了。包括一系列的线程控制等等。(三)断点续传内核的实现主要用了6个类,包括一个测试类。sitefilefetch.java负责整个文件的抓取,控制内部线程(filesplitterfetch类)。filesplitterfetch.java负责部分文件的抓取。fileaccess.java负责文件的存储。siteinfobean.java要抓取的文件的信息,如文件保存的目录,名字,抓取文件的url等。utility.java工具类,放一些简单的方法。testmethod.java测试类。下面是源程序: /***sitefilefetch.java*/package netfox;import java.io.*;import java.net.*;public class sitefilefetch extends thread {siteinfobean siteinfobean = null; //文件信息beanlong[] nstartpos; //开始位置long[] nendpos; //结束位置filesplitterfetch[] filesplitterfetch; //子线程对象long nfilelength; //文件长度boolean bfirst = true; //是否第一次取文件boolean bstop = false; //停止标志file tmpfile; //文件下载的临时信息dataoutputstream output; //输出到文件的输出流public sitefilefetch(siteinfobean bean) throws ioexception{siteinfobean = bean;//tmpfile = file.createtempfile ("zhong","1111",new file(bean.getsfilepath()));tmpfile = new file(bean.getsfilepath()+file.separator + bean.getsfilename()+".info");if(tmpfile.exists ()){bfirst = false;read_npos();}else{nstartpos = new long[bean.getnsplitter()];nendpos = new long[bean.getnsplitter()];}}public void run(){//获得文件长度//分割文件//实例filesplitterfetch//启动filesplitterfetch线程//等待子线程返回try{if(bfirst){nfilelength = getfilesize();if(nfilelength == -1){system.err.println("file length is not known!");}else if(nfilelength == -2){system.err.println("file is not access!");}else{for(int i=0;i<nstartpos.length;i++){nstartpos = (long)(i*(nfilelength/nstartpos.length));}for(int i=0;i<nendpos.length-1;i++){nendpos = nstartpos[i+1];}nendpos[nendpos.length-1] = nfilelength;}}//启动子线程filesplitterfetch = new filesplitterfetch[nstartpos.length];for(int i=0;i<nstartpos.length;i++){filesplitterfetch = new filesplitterfetch(siteinfobean.getssiteurl(),siteinfobean.getsfilepath() + file.separator + siteinfobean.getsfilename(),nstartpos,nendpos,i);utility.log("thread " + i + " , nstartpos = " + nstartpos + ", nendpos = " + nendpos);filesplitterfetch.start();}// filesplitterfetch[npos.length-1] = new filesplitterfetch(siteinfobean.getssiteurl(),siteinfobean.getsfilepath() + file.separator + siteinfobean.getsfilename(),npos[npos.length-1],nfilelength,npos.length-1);// utility.log("thread " + (npos.length-1) + " , nstartpos = " + npos[npos.length-1] + ",nendpos = " + nfilelength);// filesplitterfetch[npos.length-1].start();//等待子线程结束//int count = 0;//是否结束while循环boolean breakwhile = false;while(!bstop){write_npos();utility.sleep(500);breakwhile = true;for(int i=0;i4)// sitestop();}system.err.println("文件下载结束!");}catch(exception e){e.printstacktrace ();}}//获得文件长度public long getfilesize(){int nfilelength = -1;try{url url = new url(siteinfobean.getssiteurl());httpurlconnection httpconnection = (httpurlconnection)url.openconnection ();httpconnection.setrequestproperty("user-agent","netfox");int responsecode=httpconnection.getresponsecode();if(responsecode>=400){processerrorcode(responsecode);return -2; //-2 represent access is error}string sheader;for(int i=1;;i++){//datainputstream in = new datainputstream(httpconnection.getinputstream ());//utility.log(in.readline());sheader=httpconnection.getheaderfieldkey(i);if(sheader!=null){if(sheader.equals("content-length")){nfilelength = integer.parseint(httpconnection.getheaderfield(sheader));break;}}elsebreak;}}catch(ioexception e){e.printstacktrace ();}catch(exception e){e.printstacktrace ();}utility.log(nfilelength);return nfilelength;}//保存下载信息(文件指针位置)private void write_npos(){try{output = new dataoutputstream(new fileoutputstream(tmpfile));output.writeint(nstartpos.length);for(int i=0;i<nstartpos.length;i++){// output.writelong(npos);output.writelong(filesplitterfetch.nstartpos);output.writelong(filesplitterfetch.nendpos);}output.close();}catch(ioexception e){e.printstacktrace ();}catch(exception e){e.printstacktrace ();}}//读取保存的下载信息(文件指针位置)private void read_npos(){try{datainputstream input = new datainputstream(new fileinputstream(tmpfile));int ncount = input.readint();nstartpos = new long[ncount];nendpos = new long[ncount];for(int i=0;i<nstartpos.length;i++){nstartpos = input.readlong();nendpos = input.readlong();}input.close();}catch(ioexception e){e.printstacktrace ();}catch(exception e){e.printstacktrace ();}}private void processerrorcode(int nerrorcode){system.err.println("error code : " + nerrorcode);}//停止文件下载public void sitestop(){bstop = true;for(int i=0;i<nstartpos.length;i++)filesplitterfetch.splitterstop();}}/***filesplitterfetch.java*/package netfox;import java.io.*;import java.net.*;public class filesplitterfetch extends thread {string surl; //file urllong nstartpos; //file snippet start positionlong nendpos; //file snippet end positionint nthreadid; //threads idboolean bdownover = false; //downing is overboolean bstop = false; //stop identicalfileaccessi fileaccessi = null; //file access interfacepublic filesplitterfetch(string surl,string sname,long nstart,long nend,int id) throws ioexception{this.surl = surl;this.nstartpos = nstart;this.nendpos = nend;nthreadid = id;fileaccessi = new fileaccessi(sname,nstartpos);}public void run(){while(nstartpos < nendpos && !bstop){try{url url = new url(surl);httpurlconnection httpconnection = (httpurlconnection)url.openconnection ();httpconnection.setrequestproperty("user-agent","netfox");string sproperty = "bytes="+nstartpos+"-";httpconnection.setrequestproperty("range",sproperty);utility.log(sproperty);inputstream input = httpconnection.getinputstream();//logresponsehead(httpconnection);byte[] b = new byte[1024];int nread;while((nread=input.read(b,0,1024)) > 0 && nstartpos < nendpos && !bstop){nstartpos += fileaccessi.write(b,0,nread);//if(nthreadid == 1)// utility.log("nstartpos = " + nstartpos + ", nendpos = " + nendpos);}utility.log("thread " + nthreadid + " is over!");bdownover = true;//npos = fileaccessi.write (b,0,nread);}catch(exception e){e.printstacktrace ();}}}//打印回应的头信息public void logresponsehead(httpurlconnection con){for(int i=1;;i++){string header=con.getheaderfieldkey(i);if(header!=null)//responseheaders.put(header,httpconnection.getheaderfield(header));utility.log(header+" : "+con.getheaderfield(header));elsebreak;}}public void splitterstop(){bstop = true;}}/***fileaccess.java*/package netfox;import java.io.*;public class fileaccessi implements serializable{randomaccessfile osavedfile;long npos;public fileaccessi() throws ioexception{this("",0);}public fileaccessi(string sname,long npos) throws ioexception{osavedfile = new randomaccessfile(sname,"rw");this.npos = npos;osavedfile.seek(npos);}public synchronized int write(byte[] b,int nstart,int nlen){int n = -1;try{osavedfile.write(b,nstart,nlen);n = nlen;}catch(ioexception e){e.printstacktrace ();}return n;}}/***siteinfobean.java*/package netfox;public class siteinfobean {private string ssiteurl; //sites urlprivate string sfilepath; //saved files pathprivate string sfilename; //saved files nameprivate int nsplitter; //count of splited downloading filepublic siteinfobean(){//default value of nsplitter is 5this("","","",5);}public siteinfobean(string surl,string spath,string sname,int nspiltter){ssiteurl= surl;sfilepath = spath;sfilename = sname;this.nsplitter = nspiltter;}public string getssiteurl(){return ssiteurl;}public void setssiteurl(string value){ssiteurl = value;}public string getsfilepath(){return sfilepath;}public void setsfilepath(string value){sfilepath = value;}public string getsfilename(){return sfilename;}public void setsfilename(string value){sfilename = value;}public int getnsplitter(){return nsplitter;}public void setnsplitter(int ncount){nsplitter = ncount;}}/***utility.java*/package netfox;public class utility {public utility(){}public static void sleep(int nsecond){try{thread.sleep(nsecond);}catch(exception e){e.printstacktrace ();}}public static void log(string smsg){system.err.println(smsg);}public static void log(int smsg){system.err.println(smsg);}}/***testmethod.java*/package netfox;public class testmethod {public testmethod(){ ///xx/weblogic60b2_win.exetry{siteinfobean bean = new siteinfobean("http://localhost/xx/weblogic60b2_win.exe","l:\\temp","weblogic60b2_win.exe",5);//siteinfobean bean = new siteinfobean("http://localhost:8080/down.zip","l:\\temp","weblogic60b2_win.exe",5);sitefilefetch filefetch = new sitefilefetch(bean);filefetch.start();}catch(exception e){e.printstacktrace ();}}public static void main(string[] args){new testmethod();}}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值