(1) Prinsip pengunduhan yang dapat dilanjutkan <BR>Sebenarnya prinsip pengunduhan yang dapat dilanjutkan sangat sederhana, hanya saja permintaan HTTP berbeda dengan pengunduhan pada umumnya.
Misalnya, ketika browser meminta file di server, permintaan yang dibuatnya adalah sebagai berikut:
Asumsikan nama domain server adalah wwww.sjtu.edu.cn dan nama filenya adalah down.zip.
DAPATKAN /down.zip HTTP/1.1
Terima: gambar/gif, gambar/x-xbitmap, gambar/jpeg, gambar/pjpeg, application/vnd.ms-
excel, aplikasi/msword, aplikasi/vnd.ms-powerpoint, */*
Bahasa Terima: zh-cn
Terima-Encoding: gzip, mengempis
Agen Pengguna: Mozilla/4.0 (kompatibel; MSIE 5.01; Windows NT 5.0)
Koneksi: Tetap Hidup
Setelah server menerima permintaan, ia mencari file yang diminta sesuai kebutuhan, mengekstrak informasi file, dan kemudian mengembalikannya ke browser
200
Panjang Konten=106786028
Rentang Terima=byte
Tanggal=Senin, 30 Apr 2001 12:56:11 GMT
ETag=W/"02ca57e173c11:95b"
Tipe-Konten=aplikasi/aliran oktet
Server=Microsoft-IIS/5.0
Terakhir Dimodifikasi=Senin, 30 Apr 2001 12:56:11 GMT
Yang disebut pengunduhan resume berarti melanjutkan pengunduhan dari titik di mana file telah diunduh. Jadi di pass browser klien
Ketika berbicara tentang server web, satu informasi lagi perlu ditambahkan - mulai dari mana.
Berikut ini adalah "browser" yang saya kompilasi sendiri untuk meneruskan informasi permintaan ke server Web. Permintaan dimulai dari 2000070 byte.
DAPATKAN /down.zip HTTP/1.0
Agen Pengguna: NetFox
RANGE: byte=2000070-
Terima: teks/html, gambar/gif, gambar/jpeg, *; q=.2, */*;
Jika Anda perhatikan dengan teliti, Anda akan menemukan baris tambahan RANGE: bytes=2000070-
Arti dari baris ini adalah untuk memberitahu server bahwa file down.zip akan dikirimkan mulai dari 2000070 byte, dan byte sebelumnya tidak perlu dikirimkan.
Setelah server menerima permintaan ini, informasi yang dikembalikan adalah sebagai berikut:
206
Panjang Konten=106786028
Rentang Konten=byte 2000070-106786027/106786028
Tanggal=Senin, 30 Apr 2001 12:55:20 GMT
ETag=W/"02ca57e173c11:95b"
Tipe-Konten=aplikasi/aliran oktet
Server=Microsoft-IIS/5.0
Terakhir Dimodifikasi=Senin, 30 Apr 2001 12:55:20 GMT
Membandingkannya dengan informasi yang dikembalikan oleh server sebelumnya, Anda akan menemukan bahwa sebuah baris telah ditambahkan:
Rentang Konten=byte 2000070-106786027/106786028
Kode pengembalian juga telah diubah menjadi 206, bukan 200.
Mengetahui prinsip-prinsip di atas, Anda dapat memprogram pengunduhan resume breakpoint.
(2) Poin-poin penting dalam penerapan transfer resume breakpoint di Jawa
(1) Metode apa yang digunakan untuk mengirimkan RANGE: bytes=2000070-.
Tentu saja, ini pasti bisa dilakukan dengan menggunakan Socket asli, tapi itu akan terlalu merepotkan. Faktanya, paket net Java menyediakan fungsi ini. Kodenya adalah sebagai berikut:
URL url = URL baru("http://www.sjtu.edu.cn/down.zip");
HttpURLConnection httpConnection = (HttpURLConnection)url.openConnection();
//Setel Agen-Pengguna
httpConnection.setRequestProperty("Agen-Pengguna","NetFox");
//Atur posisi awal transmisi resume breakpoint
httpConnection.setRequestProperty("RANGE","bytes=2000070");
//Dapatkan aliran masukan
InputStream masukan = httpConnection.getInputStream();
Aliran byte yang diambil dari aliran input adalah aliran byte yang dimulai dari 2000070 di file down.zip.
Soalnya, sebenarnya sangat mudah untuk mengimplementasikan transfer resume breakpoint di Java.
Hal selanjutnya yang harus dilakukan adalah bagaimana menyimpan aliran yang diperoleh ke sebuah file.
Metode yang digunakan untuk menyimpan file.
Saya menggunakan kelas RandAccessFile dalam paket IO.
Pengoperasiannya cukup sederhana. Asumsikan file tersebut disimpan mulai dari 2000070. Kodenya adalah sebagai berikut:
Copy kode kodenya sebagai berikut:
RandomAccess oSavedFile = new RandomAccessFile("down.zip","rw");
nPos panjang = 2000070;
//Cari penunjuk file ke posisi nPos
oSavedFile.seek(nPos);
byte[] b = byte baru[1024];
int nBaca;
//Baca aliran byte dari aliran input dan tulis ke file
while((nRead=input.read(b,0,1024)) > 0)
{
oSavedFile.write(b,0,nBaca);
}
Bagaimanapun, ini sangat sederhana.
Hal berikutnya yang harus dilakukan adalah mengintegrasikannya ke dalam program yang lengkap. Termasuk serangkaian kontrol benang dan sebagainya.
(3) Implementasi kernel resume breakpoint <BR>terutama menggunakan 6 kelas, termasuk kelas pengujian.
SiteFileFetch.java bertanggung jawab untuk mengambil seluruh file dan mengendalikan thread internal (kelas FileSplitterFetch).
FileSplitterFetch.java bertanggung jawab untuk mengambil beberapa file.
FileAccess.java bertanggung jawab atas penyimpanan file.
Informasi tentang file yang ingin dirayapi SiteInfoBean.java, seperti direktori tempat file disimpan, namanya, URL file yang dirayapi, dll.
Kelas alat Utility.java, masukkan beberapa metode sederhana.
Kelas tes TestMethod.java.
Berikut ini adalah sumber programnya:
Copy kode kodenya sebagai berikut:
/*
**SiteFileFetch.java
*/
paket NetFox;
import java.io.*;
impor java.net.*;
kelas publik SiteFileFetch memperluas Thread {
SiteInfoBean siteInfoBean = null; //Informasi file Bean
panjang[] nStartPos; //Posisi awal
long[] nEndPos; //Posisi akhir
FileSplitterFetch[] fileSplitterFetch; //objek sub-utas
panjang nPanjang File; //Panjang file
boolean bFirst = true; //Apakah akan mengambil file untuk pertama kalinya
boolean bStop = false; //tanda berhenti
File tmpFile; //Informasi sementara untuk pengunduhan file
Keluaran DataOutputStream; //Aliran keluaran ke file
SiteFileFetch publik (SiteInfoBean bean) menampilkan IOException
{
siteInfoBean = kacang;
//tmpFile = File.createTempFile ("zhong","1111",File baru(bean.getSFilePath()));
tmpFile = File baru(bean.getSFilePath()+File.separator + bean.getSFileName()+".info");
if(tmpFile.ada ())
{
bPertama = salah;
baca_nPos();
}
kalau tidak
{
nStartPos = panjang baru[bean.getNSplitter()];
nEndPos = panjang baru[bean.getNSplitter()];
}
}
menjalankan kekosongan publik()
{
//Dapatkan panjang file
//membagi berkas
//Instance FileSplitterFetch
//Mulai thread FileSplitterFetch
//Tunggu hingga thread anak kembali
mencoba{
jika(bPertama)
{
nPanjang File = getFileSize();
jika(nPanjang File == -1)
{
System.err.println("Panjang File tidak diketahui!");
}
lain jika(nPanjang File == -2)
{
System.err.println("File tidak dapat diakses!");
}
kalau tidak
{
for(int i=0;i<nStartPos.panjang;i++)
{
nStartPos[i] = (panjang)(i*(nFileLength/nStartPos.length));
}
for(int i=0;i<nEndPos.panjang-1;i++)
{
nEndPos[i] = nStartPos[i+1];
}
nEndPos[nEndPos.length-1] = nPanjang File;
}
}
//Mulai thread anak
fileSplitterFetch = FileSplitterFetch baru[nStartPos.length];
for(int i=0;i<nStartPos.panjang;i++)
{
fileSplitterFetch[i] = FileSplitterFetch baru(siteInfoBean.getSSiteURL(),
siteInfoBean.getSFilePath() + File.separator + siteInfoBean.getSFileName(),
nMulaiPos[i],nEndPos[i],i);
Utility.log("Utas " + i + " , nStartPos = " + nStartPos[i] + ", nEndPos = " + nEndPos[i]);
fileSplitterFetch[i].mulai();
}
// fileSplitterFetch[nPos.length-1] = FileSplitterFetch baru(siteInfoBean.getSSiteURL(),
siteInfoBean.getSFilePath() + File.separator + siteInfoBean.getSFileName(),nPos[nPos.length-1],nFileLength,nPos.length-1);
// Utility.log("Utas " + (nPos.panjang-1) + " , nStartPos = " + nPos[nPos.panjang-1] + ",
nEndPos = " + nPanjang File);
// fileSplitterFetch[nPos.length-1].mulai();
//Tunggu hingga thread anak berakhir
//int hitungan = 0;
//Apakah akan mengakhiri perulangan while
boolean breakWhile = salah;
sementara(!bBerhenti)
{
tulis_nPos();
Utilitas.tidur(500);
breakWhile = benar;
for(int i=0;i<nStartPos.panjang;i++)
{
jika(!fileSplitterFetch[i].bDownOver)
{
breakWhile = salah;
merusak;
}
}
jika(breakWhile)
merusak;
//hitung++;
//jika(hitung>4)
// situsBerhenti();
}
System.err.println("Pengunduhan file selesai!");
}
catch(Pengecualian e){e.printStackTrace();}
}
//Dapatkan panjang file
getFileSize() panjang publik
{
int nPanjang File = -1;
mencoba{
URL url = URL baru(siteInfoBean.getSSiteURL());
HttpURLConnection httpConnection = (HttpURLConnection)url.openConnection();
httpConnection.setRequestProperty("Agen-Pengguna","NetFox");
int responCode=httpConnection.getResponseCode();
jika(Kode Respon>=400)
{
prosesErrorCode(responseCode);
return -2; //-2 menunjukkan akses adalah kesalahan
}
String sHeader;
untuk(ke dalam i=1;;i++)
{
//DataInputStream di = new DataInputStream(httpConnection.getInputStream());
//Utility.log(di.readLine());
sHeader=httpConnection.getHeaderFieldKey(i);
jika(sHeader!=null)
{
if(sHeader.equals("Panjang Konten"))
{
nFileLength = Integer.parseInt(httpConnection.getHeaderField(sHeader));
merusak;
}
}
kalau tidak
merusak;
}
}
catch(IOException e){e.printStackTrace();}
catch(Pengecualian e){e.printStackTrace();}
Utilitas.log(nPanjang File);
kembalikan nFileLength;
}
//Simpan informasi unduhan (posisi penunjuk file)
kekosongan pribadi write_nPos()
{
mencoba{
keluaran = DataOutputStream baru(FileOutputStream baru(tmpFile));
output.writeInt(nStartPos.panjang);
for(int i=0;i<nStartPos.panjang;i++)
{
// keluaran.writeLong(nPos[i]);
output.writeLong(fileSplitterFetch[i].nStartPos);
output.writeLong(fileSplitterFetch[i].nEndPos);
}
keluaran.close();
}
catch(IOException e){e.printStackTrace();}
catch(Pengecualian e){e.printStackTrace();}
}
//Baca informasi unduhan yang disimpan (posisi penunjuk file)
kekosongan pribadi read_nPos()
{
mencoba{
Masukan DataInputStream = DataInputStream baru(FileInputStream baru(tmpFile));
int nHitung = masukan.readInt();
nStartPos = panjang baru[nHitungan];
nEndPos = panjang baru[nHitungan];
for(int i=0;i<nStartPos.panjang;i++)
{
nStartPos[i] = masukan.readLong();
nEndPos[i] = masukan.readLong();
}
masukan.tutup();
}
catch(IOException e){e.printStackTrace();}
catch(Pengecualian e){e.printStackTrace();}
}
proses kekosongan pribadiErrorCode (int nErrorCode)
{
System.err.println("Kode Kesalahan : " + nErrorCode);
}
//Hentikan pengunduhan berkas
situs kekosongan publikStop()
{
bBerhenti = benar;
for(int i=0;i<nStartPos.panjang;i++)
fileSplitterFetch[i].splitterStop();
}
}
/*
**FileSplitterFetch.java
*/
paket NetFox;
import java.io.*;
impor java.net.*;
FileSplitterFetch kelas publik memperluas Thread {
String URL; //URL berkas
nStartPos panjang; //Posisi Awal Cuplikan File
nEndPos panjang; //Posisi Akhir Cuplikan File
int nID Utas; //ID Utas
boolean bDownOver = false; //Down telah berakhir
boolean bStop = false; //Berhenti identik
FileAccessI fileAccessI = null; //Antarmuka Akses File
FileSplitterFetch publik (String sURL, String sName, nStart panjang, nEnd panjang, int id) melempar IOException
{
ini.sURL = URL;
ini.nStartPos = nMulai;
ini.nEndPos = nEnd;
nThreadID = id;
fileAccessI = FileAccessI baru(sName,nStartPos);
}
menjalankan kekosongan publik()
{
while(nStartPos < nEndPos && !bStop)
{
mencoba{
URL url = URL baru(sURL);
HttpURLConnection httpConnection = (HttpURLConnection)url.openConnection();
httpConnection.setRequestProperty("Agen-Pengguna","NetFox");
String sProperti = "bytes="+nStartPos+"-";
httpConnection.setRequestProperty("RANGE",sProperty);
Utilitas.log(sProperti);
InputStream masukan = httpConnection.getInputStream();
//logResponseHead(httpKoneksi);
byte[] b = byte baru[1024];
int nBaca;
while((nRead=input.read(b,0,1024)) > 0 && nStartPos < nEndPos && !bStop)
{
nStartPos += fileAccessI.write(b,0,nBaca);
//jika(nIDUntaian == 1)
// Utilitas.log("nStartPos = " + nStartPos + ", nEndPos = " + nEndPos);
}
Utility.log("Utas " + nThreadID + " sudah berakhir!");
bDownOver = benar;
//nPos = fileAccessI.write (b,0,nBaca);
}
catch(Pengecualian e){e.printStackTrace();}
}
}
//Cetak informasi header respons
public void logResponseHead(HttpURLConnection dengan)
{
untuk(ke dalam i=1;;i++)
{
String header=con.getHeaderFieldKey(i);
jika(tajuk!=batal)
//responseHeaders.put(header,httpConnection.getHeaderField(header));
Utility.log(header+" : "+con.getHeaderField(header));
kalau tidak
merusak;
}
}
pemisah kekosongan publikStop()
{
bBerhenti = benar;
}
}
/*
**FileAccess.java
*/
paket NetFox;
import java.io.*;
FileAccessI kelas publik mengimplementasikan Serializable{
RandomAccessFile oSavedFile;
nPos panjang;
FileAccessI() publik menampilkan IOException
{
ini("",0);
}
FileAccessI publik (String sName, nPos panjang) menampilkan IOException
{
oSavedFile = new RandomAccessFile(sName,"rw");
ini.nPos = nPos;
oSavedFile.seek(nPos);
}
tulis int tersinkronisasi publik(byte[] b,int nMulai,int nLen)
{
ke dalam n = -1;
mencoba{
oSavedFile.write(b,nMulai,nLen);
n = nLen;
}
menangkap(IOException e)
{
e.printStackTrace();
}
kembali n;
}
}
/*
**SiteInfoBean.java
*/
paket NetFox;
kelas publik SiteInfoBean {
String pribadi sSiteURL; //URL situs
private String sFilePath; //Jalur File Tersimpan
private String sFileName; //Nama File Tersimpan
private int nSplitter; //Jumlah File Pengunduhan Terpisah
SiteInfoBean publik()
{
//nilai default nSplitter adalah 5
ini("","","",5);
}
SiteInfoBean publik(String sURL,String sPath,String sName,int nSpiltter)
{
sSiteURL= URL URL;
sFilePath = sPath;
sFileName = sNama;
ini.nSplitter = nSpiltter;
}
String publik getSSiteURL()
{
kembalikan sSiteURL;
}
public void setSSiteURL (Nilai string)
{
sSiteURL = nilai;
}
String publik getSFilePath()
{
kembalikan sFilePath;
}
kekosongan publik setSFilePath(Nilai string)
{
sFilePath = nilai;
}
String publik getSFileName()
{
kembalikan sFileName;
}
public void setSFileName (Nilai string)
{
sFileName = nilai;
}
int publik getNSplitter()
{
kembalikan nSplitter;
}
kekosongan publik setNSplitter(int nCount)
{
nPemisah = nHitungan;
}
}
/*
**Utilitas.java
*/
paket NetFox;
Utilitas kelas publik {
Utilitas publik()
{
}
tidur kekosongan statis publik (int nSecond)
{
mencoba{
Thread.tidur(nSecond);
}
menangkap (Pengecualian e)
{
e.printStackTrace();
}
}
log kekosongan statis publik (String sMsg)
{
Sistem.err.println(sMsg);
}
log kekosongan statis publik (int sMsg)
{
Sistem.err.println(sMsg);
}
}
/*
**Metode Tes.java
*/
paket NetFox;
Metode Tes kelas publik {
Metode Tes publik()
{ ///xx/weblogic60b2_win.exe
mencoba{
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 = SiteFileFetch baru(kacang);
fileFetch.mulai();
}
catch(Pengecualian e){e.printStackTrace();
}
}
public static void main(String[] args)
{
Metode Tes baru();
}
}