How does Java implement HTTP breakpoint continuation

  • 2020-04-01 01:09:49
  • OfStack

(a) the principle of continuation of the breakpoint
In fact, the breakpoint continuation principle is very simple, is in the Http request and the general download is different.
For example, when a browser requests a text on a server, it makes the following request:
Assume the server's domain name is wwww.sjtu.edu.cn and the file name is 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, * / *
The Accept - Language: useful - cn
The Accept - Encoding: gzip, deflate
The user-agent: Mozilla / 4.0 (compatible; MSIE 5.01; Windows NT 5.0)
Connection: Keep Alive
Upon receipt of the request, the server searches for the requested file, extracts the file information, and returns the following information to the browser
200
The Content - Length = 106786028
The Accept - Ranges = bytes
Date=Mon, 30 Apr 2001 12:56:11 GMT
ETag = W / 02 ca57e173c11:95 "b"
The content-type = application/octet stream
Server = Microsoft IIS / 5.0
Last-modified =Mon, 30 Apr 2001 12:56:11 GMT
The so-called breakpoint continuation, that is, to continue to download from the file has been downloaded from the place. So pass in the client browser
Add one more message to your Web server - where to start.
Here is a "browser" of my own code to pass the request information to the Web server, starting at 200,070 bytes.
GET/down. Zip HTTP / 1.0
The user-agent: NetFox
RANGE: bytes = 2000070 -
Accept: text/ HTML, image/ GIF, image/jpeg, *; Q = 2, * / *; Q = 2
A closer look reveals an extra line in RANGE: bytes=2000070-
This line tells the server that the down.zip file starts with 2000070 bytes, and the previous bytes are not needed.
Upon receipt of this request, the server returns the following information:
206
The Content - Length = 106786028
The Content - Range = bytes 2000070-106786027/106786028
Date=Mon, 30 Apr 2001 12:55:20 GMT
ETag = W / 02 ca57e173c11:95 "b"
The content-type = application/octet stream
Server = Microsoft IIS / 5.0
Last-modified =Mon, 30 Apr 2001 12:55:20 GMT
Compare this with the information returned from the previous server, and you will see an additional line:
The Content - Range = bytes 2000070-106786027/106786028
The return code is now 206 instead of 200.
Knowing the above principles, you can do breakpoint continuation of the programming.
(two)Java breakpoint continuation key points
(1) how to submit RANGE: bytes=2000070-.
Of course, you can do it with the original Socket, but that's a lot of work, and it's actually provided in the Java net package. The code is as follows:
URL the URL = new URL (" http://www.sjtu.edu.cn/down.zip ");
HttpURLConnection httpConnection = (HttpURLConnection) url. OpenConnection ();
/ / set the user-agent
HttpConnection. SetRequestProperty (" the user-agent ", "NetFox");
// sets the starting position of the breakpoint continuation
HttpConnection. SetRequestProperty (" RANGE "and" bytes = 2000070 ");
// get the input stream
InputStream input = httpConnection. GetInputStream ();
The stream to be taken from the input stream is the stream from the down. Zip file starting at 2000070.
You see, in fact, breakpoint continuation is very simple to implement in Java.
The next thing to do is how to save the obtained stream to the file.
The method used to save the file.
I'm using the RandAccessFile class in the IO package.
The operation is quite simple, assuming that the file is saved from 2000070. The code is as follows:
 
RandomAccess oSavedFile = new RandomAccessFile("down.zip","rw"); 
long nPos = 2000070; 
//Locate the file pointer to the nPos location
oSavedFile.seek(nPos); 
byte[] b = new byte[1024]; 
int nRead; 
//Read in the byte stream from the input stream and write to the file
while((nRead=input.read(b,0,1024)) > 0) 
{ 
oSavedFile.write(b,0,nRead); 
} 

Well, that's easy.
The next thing to do is to put it together into a complete program. Including a bunch of thread control and so on.
(3) breakpoint continuation of the implementation of the kernel
Six classes were used, including a test class.
Sitefilefetch.java is responsible for fetching the entire file, controlling the internal thread (FileSplitterFetch class).
Java is responsible for fetching some files.
Fileaccess.java is responsible for the storage of files.
Siteinfobean.java information about the file to be fetched, such as the directory where the file is saved, name, URL to be fetched, and so on.
Utility.java Utility class, put some simple methods.
Testmethod.java test class.
Here is the source program:
 
 
package NetFox; 
import java.io.*; 
import java.net.*; 
public class SiteFileFetch extends Thread { 
SiteInfoBean siteInfoBean = null; //File information Bean
long[] nStartPos; //The starting position
long[] nEndPos; //End position
FileSplitterFetch[] fileSplitterFetch; //Child thread object
long nFileLength; //The length of the file
boolean bFirst = true; //Whether to fetch the file for the first time
boolean bStop = false; //A stop sign
File tmpFile; //Temporary information for file download
DataOutputStream output; //The output stream to the file
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() 
{ 
// To obtain The length of the file
//Split the file
//Instance FileSplitterFetch
//Start the FileSplitterFetch thread
//Wait for the child thread to return
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[i] = (long)(i*(nFileLength/nStartPos.length)); 
} 
for(int i=0;i<nEndPos.length-1;i++) 
{ 
nEndPos[i] = nStartPos[i+1]; 
} 
nEndPos[nEndPos.length-1] = nFileLength; 
} 
} 
//Initiator subthread
fileSplitterFetch = new FileSplitterFetch[nStartPos.length]; 
for(int i=0;i<nStartPos.length;i++) 
{ 
fileSplitterFetch[i] = new FileSplitterFetch(siteInfoBean.getSSiteURL(), 
siteInfoBean.getSFilePath() + File.separator + siteInfoBean.getSFileName(), 
nStartPos[i],nEndPos[i],i); 
Utility.log("Thread " + i + " , nStartPos = " + nStartPos[i] + ", nEndPos = " + nEndPos[i]); 
fileSplitterFetch[i].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(); 
//Wait for the child thread to finish
//int count = 0; 
//Whether to end the while loop
boolean breakWhile = false; 
while(!bStop) 
{ 
write_nPos(); 
Utility.sleep(500); 
breakWhile = true; 
for(int i=0;i<nStartPos.length;i++) 
{ 
if(!fileSplitterFetch[i].bDownOver) 
{ 
breakWhile = false; 
break; 
} 
} 
if(breakWhile) 
break; 
//count++; 
//if(count>4) 
// siteStop(); 
} 
System.err.println(" File download over! "); 
} 
catch(Exception e){e.printStackTrace ();} 
} 
// To obtain The length of the file
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; 
} 
} 
else 
break; 
} 
} 
catch(IOException e){e.printStackTrace ();} 
catch(Exception e){e.printStackTrace ();} 
Utility.log(nFileLength); 
return nFileLength; 
} 
//Save download information (file pointer location)
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[i]); 
output.writeLong(fileSplitterFetch[i].nStartPos); 
output.writeLong(fileSplitterFetch[i].nEndPos); 
} 
output.close(); 
} 
catch(IOException e){e.printStackTrace ();} 
catch(Exception e){e.printStackTrace ();} 
} 
//Read saved download information (file pointer position)
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[i] = input.readLong(); 
nEndPos[i] = 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); 
} 
//Stop file download
public void siteStop() 
{ 
bStop = true; 
for(int i=0;i<nStartPos.length;i++) 
fileSplitterFetch[i].splitterStop(); 
} 
} 
 
package NetFox; 
import java.io.*; 
import java.net.*; 
public class FileSplitterFetch extends Thread { 
String sURL; //File URL 
long nStartPos; //File Snippet Start Position 
long nEndPos; //File Snippet End Position 
int nThreadID; //Thread's ID 
boolean bDownOver = false; //Downing is over 
boolean bStop = false; //Stop identical 
FileAccessI fileAccessI = null; //File Access interface 
public 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 ();} 
} 
} 
//Print the header information for the response
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)); 
else 
break; 
} 
} 
public void splitterStop() 
{ 
bStop = true; 
} 
} 
 
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; 
} 
} 
 
package NetFox; 
public class SiteInfoBean { 
private String sSiteURL; //Site's URL 
private String sFilePath; //Saved File's Path 
private String sFileName; //Saved File's Name 
private int nSplitter; //Count of Splited Downloading File 
public SiteInfoBean() 
{ 
//default value of nSplitter is 5 
this("","","",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; 
} 
} 
 
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); 
} 
} 
 
package NetFox; 
public class TestMethod { 
public TestMethod() 
{ ///xx/weblogic60b2_win.exe 
try{ 
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(); 
} 
} 

Related articles: