HTTP協議包讀取過程的Java實現
之前的兩篇文章中《GET實現HTTP協議請求包的分析》和《HTTP協議請求包的Java實現》對HTTP協議包的請求連接內容進行了不少的講解。那么本文將繼續做一下補充,主要是講解如何完成讀取HTTP包。
以下我自己設計的一個讀取HTTP協議包的類SocketRequest。
- public class SocketRequest
- {//從指定的Socket的InputStream中讀取數據
- private InputStreaminput;
- private Stringuri;
- private StringBufferrequest=new StringBuffer();//用于保存所有內容
- private intCONTENT_LENGTH=0;//實際包內容數據長
- private boolean bePost = false;
- private boolean beHttpResponse = false;
- private boolean beChucked = false;
- private boolean beGet = false;
- private bytecrlf13 = (byte)13; //'r'
- private bytecrlf10 = (byte)10;//'n'
- public SocketRequest(InputStream input) {
- this.input = input;}
- public SocketRequest(Socket socket) {
- this.input = socket.getInputStream();}
- public void ReadData()
- {//解析 獲得InputStream的數據
- ReadHeader();//頭部
- if(beChucked) //為Chucked
- {int ChuckSize=0;
- while((ChuckSize=getChuckSize())>0) //多個Chucked
- {readLenData(ChuckSize+2);//讀取定長數據}
- readLenData(2); //最后的2位}
- if(CONTENT_LENGTH>0)
- {readLenData(CONTENT_LENGTH);//讀取定長數據}
- uri = "";//parseUri(new String(request));}
- private void readLenData(int size)//讀取定長數據
- {int readed=0;//已經讀取數
- try{
- int available=0;//input.available(); //可讀數
- if(available>(size-readed)) available=size-readed;
- while( readed<size )
- {while(available==0){//等到有數據可讀
- available = input.available(); //可讀數}
- if(available>(size-readed)) available= size-readed; //size-readed--剩余數
- if(available>2048) available= 2048; //size-readed--剩余數
- byte[] buffer = new byte[available];
- int reading = input.read(buffer);
- request=request.append(new String(buffer,0,reading));//byte數組相加
- readed+=reading;//已讀字符
- }}catch(IOException e){System.out.println("Read readLenData Error!");} }
- private voidReadHeader() //讀取頭部 并獲得大小
- {byte[]crlf= new byte[1];
- intcrlfNum= 0;//已經連接的回車換行數 crlfNum=4為頭部結束
- try{while( input.read(crlf)!=-1 )//讀取頭部
- {if(crlf[0]==crlf13 || crlf[0]==crlf10)
- {crlfNum++; }
- else
- {crlfNum=0;} //不是則清
- request=request.append(new String(crlf,0,1));//byte數組相加
- if(crlfNum==4) break;}}
- catch(IOException e){System.out.println("Read Http Header Error!");
- return;}
- String tempStr=(new String(request)).toUpperCase();//這里我只處理了GET與POST方法
- StringstrMethod= tempStr.substring(0,4);
- if(strMethod.equals("GET ")) //前
- {beGet=true;}
- else if(strMethod.equals("POST"))
- {bePost=true;
- getContentlen_Chucked(tempStr);}
- else {System.out.println("不支持的HTTP協議包類型");}//其它的其它類型 暫不支持
- }
- private void getContentlen_Chucked(String tempStr)//獲得長度 CONTENT-LENGTH 或 是否為CHUNKED型
- {String ss1="CONTENT-LENGTH:";
- String ss2=new String("TRANSFER-ENCODING: CHUNKED");
- int clIndex= tempStr.indexOf(ss1);
- int chuckIndex = tempStr.indexOf(ss2);//為CHUNKED型
- byte requst[]= tempStr.getBytes();
- if(clIndex!=-1)
- { //從clIndex+1起至rn
- StringBuffer sb=new StringBuffer();
- for(int i=(clIndex+16);;i++)
- {if(requst[i]!=(byte)13 && requst[i]!=(byte)10 )
- {sb.append((char)requst[i]);}
- else
- break;}
- CONTENT_LENGTH=Integer.parseInt(sb.toString());//正式的HTML文件的大小
- //System.out.println("CONTENT_LENGTH=="+CONTENT_LENGTH);}
- if(chuckIndex!=-1) beChucked=true;}
- private intgetChuckSize() //Chuck大小{
- byte[]crlf= new byte[1];
- StringBuffersb1= new StringBuffer();
- intcrlfNum= 0;//已經連接的回車換行數 crlfNum=4為頭部結束
- try{while(input.read(crlf)!=-1)//讀取頭部{
- if(crlf[0]==crlf13 || crlf[0]==crlf10)
- {crlfNum++; }
- else
- {crlfNum=0;} //不是則清
- sb1.append((char)crlf[0]);
- request=request.append(new String(crlf,0,1));//byte數組相加
- if(crlfNum==2) break;}
- }catch(IOException e){
- System.out.println("Read Http Package Error!");
- return 0;}
- return Integer.parseInt((sb1.toString()).trim(),16); //16進控制
- }//通過此來進行過濾,是否為發至目標服務器的HTTP協議包
- private String parseUri(String requestString) {
- int index1, index2;
- index1 = requestString.indexOf(' ');
- if (index1 != -1) {
- index2 = requestString.indexOf(' ', index1 + 1);
- if (index2 > index1)
- return requestString.substring(index1 + 1, index2);}
- return null;}
- public String getData() {
- return request.toString();}}
使用此類:
- SocketRequest request = new SocketRequest(socket); //socket為ServerSocket.accept()返回的Socket實例
- request.ReadData();//讀取數據
- request.getData();
為什么我要用這么大的力量去讀取呢,尤其是在因為Socket連接在發送數據時,由于網絡的原因經常會發生延遲現象,可能在服務器端開始接收數據時可能只有部分數據可以從InputStream中獲得,在一些地方處理不當時,可能只能獲得不完整的數據或是錯誤的數據。
從InputStream讀取字節時有多種辦法:
常用int read()與int read(byte[] b)。在用read(byte[])時,程序員經常會犯錯誤,因為在網絡環境中,讀取的數據量不一定等于參數的大小。




















