HTTP協議簡介和多線程斷點續傳(轉)
HTTP協議是一種超文本傳輸協議(Hypertext Transfer Protocol),工作於網絡應用層,自1990年起廣泛應用於WWW 的全球信息服務,HTTP協議的詳細說明可以在網上查閱RFC2518、RFC2616等文檔。
HTTP 協議老的標準是HTTP/1.0,目前最通用的標準是HTTP/1.1。HTTP/1.1是在HTTP/1.0基礎上的升級,增加了一些功能,全面兼容 HTTP/1.0。HTTP/1.0不支持文件斷點續傳,如果服務器使用HTTP/1.0,“網絡螞蟻”的任何多線程下載程序都只能按單線程下載;好在目 前的Web服務器絕大多數都採用了HTTP/1.1,所以,下面將基於HTTP/1.1進行介紹。
HTTP協議的相關重要命令
基於HTTP的瀏覽器瀏覽網頁、下載文件時,工作原理類似客戶機/服務器模式:瀏覽器向Web服務器發出一個HTTP請求行;Web服務器在 收到有效的請求後,返回一個狀態行或多個響應標題、一個空白行和相關文檔。根據這一工作原理,下載程序必須實現向服務器發送請求和獲取服務器響應狀態的功 能。
1.向服務器發送 GET請求命令
一個HTTP請求由一個請求行、可選數目的請求標題、一個空白行,以及在POST情況下的一些額外的數據組成。請求行的格式是:
請求方法 URI HTTP/版本號
GET 命令是瀏覽器常用的文檔請求方法,在程序中間使用
GET URI HTTP/1.1
向Web服務器發送請求行(行號3),Java 代碼如下:
....
clientSocket = new Socket(host, port);//打開要下載文件服務器的Socket
outStream = new PrintStream(clientSocket.getOutputStream());
....
outStream.println(“GET”+uri+“ HTTP/1.1”);
outStream.println(“Host:”+host);
outStream.println(“Accept:*/* ”);
outStream.println(“Referer:”);
outStream.println();
....
注:第4行給出URL中的主機名和端口號,第5行說明客戶端接收所有MIME類型,第7行方送一個空白行,表明請求行結束。
2.獲取服務器響應狀態
在發送HTTP請求行以後,程序就可以讀取服務器的響應狀態了。HTTP響應狀態行包括:HTTP 狀態碼和一些HTTP響應標題。
1) HTTP狀態碼
HTTP狀態碼格式是 HTTP/版本信息的數字表示。狀態碼例子如下:
HTTP/1.0 200 OK // 表示服務器支持HTTP/1.0 協議,成功
HTTP/1.1 200 OK // 表示服務器支持HTTP/1.1 協議,成功
HTTP/1.0 404 Not Found // 表示服務器支持HTTP/1.0 協議,訪問文件沒有找到
在程序中間,如果讀到“HTTP/1.1 200 OK”這樣的字符串,表明欲下載文件存在、該服務器支持斷點續傳,可以使用多線程下載。如果讀到“HTTP/1.0 200 OK”這樣的字符串,表明欲下載文件存在、但該服務器不支持斷點續傳,只可以使用單線程下載。
.....
while ((line=inStream.readLine()) != null) //將服務器響應狀態讀到line
........
if(line.substring(0,7).equals(“HTTP/1.”) ) //判斷是否支持HTTP/1.1
{ if(line.charAt(7)==‘0’)
{
System.out.println(“server use http/1.0”);
threadcount=1;
}
if(!(line.substring(9,12)).equals(“200”)) //判斷請求是否成功
{ System.out.println(“ERROR:”+line);
return false;
}
}
2) 讀取重要的響應標題,獲得要下載文檔的文件長度
如果HTTP狀態碼錶明訪問成功,服務器會回送一些標題行,我們最關注的是Content-Length 這一行,比如,如果服務器回送“Content-Length:1000”,表明請求文件的長度是1000字節,所以讀取這一行信息,可以得到文件的長度信息:
....
if(line.substring(0,15).equals(“Content-Length:”) )
{ filelength=Long.parseLong(line.substring(15).trim());
System.out.println(“file length:” +filelength);
}
......
向服務器發送斷點續傳請求
如上所述,如果服務器支持HTTP/1.1,再次向服務器發送GET請求:
.....
outStream.println(“GET ”+uri+“HTTP/1.1 ”);
outStream.println(“Host:”+host);
outStream.println(“Accept:*/* ”);
outStream.println(“RANGE:bytes=”+(fileblocklength)*thisthreadid+“-”);
outStream.println();
.....
第4行是關鍵,“RANGE:bytes=”是HTTP/1.1新增內容,HTTP/1.0每次傳送文件都是從文件頭開始,即0字節處開始,“RANGE:bytes=XXXX”表示要求服務器從文件XXXX字節處開始傳送,這就是我們平時所說的斷點續傳!
分割文件,多線程下載
使用多線程編程技術,同時啓動多個線程,根據線程個數,計算文件分割位置,向服務器發送幾個不同的下載斷點,同時接受數據並寫入文件,就可以實現多線程下載了。
.....
raf=new RandomAccessFile(file,“rw”);//以隨機存取方式打開文件
.....
synchronized(raf) //按同步方式把各個線程得到數據分別寫入文件
{ raf.seek(thisthreadid*(filelength/threadcount)+k*buflength);
raf.write(readbytes);
......
}
......
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
下面是用PHP模擬的POST中的構造Http協議部分
$request = "POST /happy/member.php HTTP/1.1rn";
$request .= "Pragma: no cachern";
$request .= "Host: phpx.comrn";
$request .= "User-Agent: " . $_SERVER['HTTP_USER_AGENT'] . "rn";
$request .= "Accept: */*rn";
$request .= "Accept-Language: " . $_SERVER['HTTP_ACCEPT_LANGUAGE'] . "rn";
$request .= "Keep-Alive: 300rn";
$request .= "Connection: keep-alivern";
$request .= "Cache-Control: max-age=0rn";
$request .= "Content-Type: application/x-www-form-urlencodedrn";
$request .= "Content-Length: $lenghtrn";
$request .= "rn";
$request .= $postValues;
====================================
下面是響應成功返回的信息
HTTP/1.1 200 OK
Date: Fri, 05 Nov 2004 01:06:59 GMT
Server: Apache
Set-Cookie: bblastvisit=1099616819; expires=Sat, 05-Nov-2005 01:06:59 GMT; path=/
Set-Cookie: bbuserid=17027; expires=Sat, 05-Nov-2005 01:06:59 GMT; path=/
Set-Cookie: bbpassword=3332def6f45e948bd403276b3b2002d4; expires=Sat, 05-Nov-2005 01:06:59 GMT; path=/
Set-Cookie: sessionhash=53a2b0ee3798fe2ca15342541b62f823; path=/
Content-Length: 3325
Keep-Alive: timeout=5, max=100
Connection: Keep-Alive
Content-Type: text/html; charset=GB2312
[color=darkblue][/color]
HTTP 協議老的標準是HTTP/1.0,目前最通用的標準是HTTP/1.1。HTTP/1.1是在HTTP/1.0基礎上的升級,增加了一些功能,全面兼容 HTTP/1.0。HTTP/1.0不支持文件斷點續傳,如果服務器使用HTTP/1.0,“網絡螞蟻”的任何多線程下載程序都只能按單線程下載;好在目 前的Web服務器絕大多數都採用了HTTP/1.1,所以,下面將基於HTTP/1.1進行介紹。
HTTP協議的相關重要命令
基於HTTP的瀏覽器瀏覽網頁、下載文件時,工作原理類似客戶機/服務器模式:瀏覽器向Web服務器發出一個HTTP請求行;Web服務器在 收到有效的請求後,返回一個狀態行或多個響應標題、一個空白行和相關文檔。根據這一工作原理,下載程序必須實現向服務器發送請求和獲取服務器響應狀態的功 能。
1.向服務器發送 GET請求命令
一個HTTP請求由一個請求行、可選數目的請求標題、一個空白行,以及在POST情況下的一些額外的數據組成。請求行的格式是:
請求方法 URI HTTP/版本號
GET 命令是瀏覽器常用的文檔請求方法,在程序中間使用
GET URI HTTP/1.1
向Web服務器發送請求行(行號3),Java 代碼如下:
....
clientSocket = new Socket(host, port);//打開要下載文件服務器的Socket
outStream = new PrintStream(clientSocket.getOutputStream());
....
outStream.println(“GET”+uri+“ HTTP/1.1”);
outStream.println(“Host:”+host);
outStream.println(“Accept:*/* ”);
outStream.println(“Referer:”);
outStream.println();
....
注:第4行給出URL中的主機名和端口號,第5行說明客戶端接收所有MIME類型,第7行方送一個空白行,表明請求行結束。
2.獲取服務器響應狀態
在發送HTTP請求行以後,程序就可以讀取服務器的響應狀態了。HTTP響應狀態行包括:HTTP 狀態碼和一些HTTP響應標題。
1) HTTP狀態碼
HTTP狀態碼格式是 HTTP/版本信息的數字表示。狀態碼例子如下:
HTTP/1.0 200 OK // 表示服務器支持HTTP/1.0 協議,成功
HTTP/1.1 200 OK // 表示服務器支持HTTP/1.1 協議,成功
HTTP/1.0 404 Not Found // 表示服務器支持HTTP/1.0 協議,訪問文件沒有找到
在程序中間,如果讀到“HTTP/1.1 200 OK”這樣的字符串,表明欲下載文件存在、該服務器支持斷點續傳,可以使用多線程下載。如果讀到“HTTP/1.0 200 OK”這樣的字符串,表明欲下載文件存在、但該服務器不支持斷點續傳,只可以使用單線程下載。
.....
while ((line=inStream.readLine()) != null) //將服務器響應狀態讀到line
........
if(line.substring(0,7).equals(“HTTP/1.”) ) //判斷是否支持HTTP/1.1
{ if(line.charAt(7)==‘0’)
{
System.out.println(“server use http/1.0”);
threadcount=1;
}
if(!(line.substring(9,12)).equals(“200”)) //判斷請求是否成功
{ System.out.println(“ERROR:”+line);
return false;
}
}
2) 讀取重要的響應標題,獲得要下載文檔的文件長度
如果HTTP狀態碼錶明訪問成功,服務器會回送一些標題行,我們最關注的是Content-Length 這一行,比如,如果服務器回送“Content-Length:1000”,表明請求文件的長度是1000字節,所以讀取這一行信息,可以得到文件的長度信息:
....
if(line.substring(0,15).equals(“Content-Length:”) )
{ filelength=Long.parseLong(line.substring(15).trim());
System.out.println(“file length:” +filelength);
}
......
向服務器發送斷點續傳請求
如上所述,如果服務器支持HTTP/1.1,再次向服務器發送GET請求:
.....
outStream.println(“GET ”+uri+“HTTP/1.1 ”);
outStream.println(“Host:”+host);
outStream.println(“Accept:*/* ”);
outStream.println(“RANGE:bytes=”+(fileblocklength)*thisthreadid+“-”);
outStream.println();
.....
第4行是關鍵,“RANGE:bytes=”是HTTP/1.1新增內容,HTTP/1.0每次傳送文件都是從文件頭開始,即0字節處開始,“RANGE:bytes=XXXX”表示要求服務器從文件XXXX字節處開始傳送,這就是我們平時所說的斷點續傳!
分割文件,多線程下載
使用多線程編程技術,同時啓動多個線程,根據線程個數,計算文件分割位置,向服務器發送幾個不同的下載斷點,同時接受數據並寫入文件,就可以實現多線程下載了。
.....
raf=new RandomAccessFile(file,“rw”);//以隨機存取方式打開文件
.....
synchronized(raf) //按同步方式把各個線程得到數據分別寫入文件
{ raf.seek(thisthreadid*(filelength/threadcount)+k*buflength);
raf.write(readbytes);
......
}
......
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
下面是用PHP模擬的POST中的構造Http協議部分
$request = "POST /happy/member.php HTTP/1.1rn";
$request .= "Pragma: no cachern";
$request .= "Host: phpx.comrn";
$request .= "User-Agent: " . $_SERVER['HTTP_USER_AGENT'] . "rn";
$request .= "Accept: */*rn";
$request .= "Accept-Language: " . $_SERVER['HTTP_ACCEPT_LANGUAGE'] . "rn";
$request .= "Keep-Alive: 300rn";
$request .= "Connection: keep-alivern";
$request .= "Cache-Control: max-age=0rn";
$request .= "Content-Type: application/x-www-form-urlencodedrn";
$request .= "Content-Length: $lenghtrn";
$request .= "rn";
$request .= $postValues;
====================================
下面是響應成功返回的信息
HTTP/1.1 200 OK
Date: Fri, 05 Nov 2004 01:06:59 GMT
Server: Apache
Set-Cookie: bblastvisit=1099616819; expires=Sat, 05-Nov-2005 01:06:59 GMT; path=/
Set-Cookie: bbuserid=17027; expires=Sat, 05-Nov-2005 01:06:59 GMT; path=/
Set-Cookie: bbpassword=3332def6f45e948bd403276b3b2002d4; expires=Sat, 05-Nov-2005 01:06:59 GMT; path=/
Set-Cookie: sessionhash=53a2b0ee3798fe2ca15342541b62f823; path=/
Content-Length: 3325
Keep-Alive: timeout=5, max=100
Connection: Keep-Alive
Content-Type: text/html; charset=GB2312
[color=darkblue][/color]
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.