之前的两篇文章中《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[])时,程序员经常会犯错误,因为在网络环境中,读取的数据量不一定等于参数的大小。