本文介紹了如何使用Java編寫下載軟件並實現多現程下載
網絡螞蟻Falshget 等許多多線程下載軟件都是網友的必備工具利用這些工具可以快速從服務器上下載比較大的文件這些工具的工作特性是把服務器端的文件分成幾個段每個段分別同時進行下載編寫這類程序第一必須對HTTP協議有較為充分的了解第二有效使用多線程編程手段在軟件上實現
HTTP 協議的簡介
HTTP協議是一種超文本傳輸協議(Hypertext Transfer Protocol)工作於網絡應用層自年起廣泛應用於WWW 的全球信息服務HTTP協議的詳細說明可以在網上查閱RFCRFC等文檔
HTTP 協議老的標准是HTTP/目前最通用的標准是HTTP/HTTP/是在HTTP/基礎上的升級增加了一些功能全面兼容HTTP/HTTP/不支持文件斷點續傳如果服務器使用HTTP/網絡螞蟻的任何多線程下載程序都只能按單線程下載好在目前的Web服務器絕大多數都采用了HTTP/所以下面將基於HTTP/進行介紹
HTTP協議的相關重要命令
基於HTTP的浏覽器浏覽網頁下載文件時工作原理類似客戶機/服務器模式浏覽器向Web服務器發出一個HTTP請求行Web服務器在收到有效的請求後返回一個狀態行或多個響應標題一個空白行和相關文檔根據這一工作原理下載程序必須實現向服務器發送請求和獲取服務器響應狀態的功能
向服務器發送 GET請求命令
一個HTTP請求由一個請求行可選數目的請求標題一個空白行以及在POST情況下的一些額外的數據組成請求行的格式是
請求方法 URI HTTP/版本號
GET 命令是浏覽器常用的文檔請求方法在程序中間使用
GET URI HTTP/
向Web服務器發送請求行(行號)Java 代碼如下
……
clientSocket = new Socket(host port)//打開要下載文件服務器的Socket
outStream = new PrintStream(clientSocketgetOutputStream())
……
outStreamprintln(GET+uri+ HTTP/)
outStreamprintln(Host+host)
outStreamprintln(Accept*/* )
outStreamprintln(Referer)
outStreamprintln()
……
注第行給出URL中的主機名和端口號第行說明客戶端接收所有MIME類型第行方送一個空白行表明請求行結束
獲取服務器響應狀態
在發送HTTP請求行以後程序就可以讀取服務器的響應狀態了HTTP響應狀態行包括HTTP 狀態碼和一些HTTP響應標題
) HTTP狀態碼
HTTP狀態碼格式是 HTTP/版本信息的數字表示狀態碼例子如下
HTTP/ OK // 表示服務器支持HTTP/ 協議成功
HTTP/ OK // 表示服務器支持HTTP/ 協議成功
HTTP/ Not Found // 表示服務器支持HTTP/ 協議訪問文件沒有找到
在程序中間如果讀到HTTP/ OK這樣的字符串表明欲下載文件存在該服務器支持斷點續傳可以使用多線程下載如果讀到HTTP/ OK這樣的字符串表明欲下載文件存在但該服務器不支持斷點續傳只可以使用單線程下載
……
while ((line=inStreamreadLine()) != null) //將服務器響應狀態讀到line
……
if(linesubstring()equals(HTTP/) ) //判斷是否支持HTTP/
{ if(linecharAt()==)
{
Systemoutprintln(server use )
threadcount=
}
if(!(linesubstring())equals()) //判斷請求是否成功
{ Systemoutprintln(ERROR+line)
return false
}
}
) 讀取重要的響應標題獲得要下載文檔的文件長度
如果HTTP狀態碼表明訪問成功服務器會回送一些標題行我們最關注的是ContentLength 這一行比如如果服務器回送ContentLength表明請求文件的長度是1000字節所以讀取這一行信息可以得到文件的長度信息
……
if(linesubstring()equals(ContentLength) )
{ filelength=LongparseLong(linesubstring()trim())
Systemoutprintln(file length +filelength)
}
……
向服務器發送斷點續傳請求
如上所述如果服務器支持HTTP/再次向服務器發送GET請求
……
outStreamprintln(GET +uri+HTTP/ )
outStreamprintln(Host+host)
outStreamprintln(Accept*/* )
outStreamprintln(RANGEbytes=+(fileblocklength)*thisthreadid+)
outStreamprintln()
……
第行是關鍵RANGEbytes=是HTTP/新增內容HTTP/每次傳送文件都是從文件頭開始即0字節處開始RANGEbytes=XXXX表示要求服務器從文件XXXX字節處開始傳送這就是我們平時所說的斷點續傳!
分割文件多線程下載
使用多線程編程技術同時啟動多個線程根據線程個數計算文件分割位置向服務器發送幾個不同的下載斷點同時接受數據並寫入文件就可以實現多線程下載了
……
raf=new RandomAccessFile(filerw)//以隨機存取方式打開文件
……
synchronized(raf) //按同步方式把各個線程得到數據分別寫入文件
{ rafseek(thisthreadid*(filelength/threadcount)+k*buflength)
rafwrite(readbytes)
……
}
……
From:http://tw.wingwit.com/Article/program/Java/hx/201311/26242.html