HTTP协议包读取过程的Java实现

网络 网络管理
首先我们在了解了前文的基础后,再来对读取HTTP协议包的代码进行一下讲解。那么这部分内容的代码比较多,希望能够帮助大家了解这部分内容。

之前的两篇文章中《GET实现HTTP协议请求包的分析》和《HTTP协议请求包的Java实现》对HTTP协议包的请求连接内容进行了不少的讲解。那么本文将继续做一下补充,主要是讲解如何完成读取HTTP包。

以下我自己设计的一个读取HTTP协议包的类SocketRequest。

  1. public class SocketRequest   
  2. {//从指定的Socket的InputStream中读取数据  
  3. private InputStreaminput;  
  4. private Stringuri;  
  5. private StringBufferrequest=new StringBuffer();//用于保存所有内容  
  6. private intCONTENT_LENGTH=0;//实际包内容数据长  
  7. private boolean bePost = false;  
  8. private boolean beHttpResponse = false;  
  9. private boolean beChucked = false;  
  10. private boolean beGet = false;  
  11. private bytecrlf13 = (byte)13; //'r'  
  12. private bytecrlf10 = (byte)10;//'n'  
  13. public SocketRequest(InputStream input) {  
  14. this.input = input;}  
  15. public SocketRequest(Socket socket) {  
  16. this.input = socket.getInputStream();}  
  17. public void ReadData()   
  18. {//解析 获得InputStream的数据   
  19. ReadHeader();//头部  
  20. if(beChucked) //为Chucked  
  21. {int ChuckSize=0;  
  22. while((ChuckSize=getChuckSize())>0) //多个Chucked  
  23. {readLenData(ChuckSize+2);//读取定长数据}  
  24. readLenData(2); //最后的2位}  
  25. if(CONTENT_LENGTH>0)  
  26. {readLenData(CONTENT_LENGTH);//读取定长数据}  
  27. uri = "";//parseUri(new String(request));}  
  28. private void readLenData(int size)//读取定长数据  
  29. {int readed=0;//已经读取数  
  30. try{  
  31. int available=0;//input.available(); //可读数  
  32. if(available>(size-readed)) available=size-readed;  
  33. while( readed<size )  
  34. {while(available==0){//等到有数据可读  
  35. available = input.available(); //可读数}  
  36. if(available>(size-readed)) available= size-readed; //size-readed--剩余数  
  37. if(available>2048) available= 2048; //size-readed--剩余数  
  38. byte[] buffer = new byte[available];  
  39. int reading = input.read(buffer);  
  40. request=request.append(new String(buffer,0,reading));//byte数组相加  
  41. readed+=reading;//已读字符  
  42. }}catch(IOException e){System.out.println("Read readLenData Error!");} }   
  43. private voidReadHeader() //读取头部 并获得大小  
  44. {byte[]crlf= new byte[1];  
  45. intcrlfNum= 0;//已经连接的回车换行数 crlfNum=4为头部结束  
  46. try{while( input.read(crlf)!=-1 )//读取头部  
  47. {if(crlf[0]==crlf13 || crlf[0]==crlf10)  
  48. {crlfNum++; }  
  49. else 
  50. {crlfNum=0;} //不是则清  
  51. request=request.append(new String(crlf,0,1));//byte数组相加  
  52. if(crlfNum==4) break;}}  
  53. catch(IOException e){System.out.println("Read Http Header Error!");  
  54. return;}  
  55. String tempStr=(new String(request)).toUpperCase();//这里我只处理了GET与POST方法  
  56. StringstrMethod= tempStr.substring(0,4);  
  57. if(strMethod.equals("GET ")) //前  
  58. {beGet=true;}  
  59. else if(strMethod.equals("POST"))  
  60. {bePost=true;  
  61. getContentlen_Chucked(tempStr);}  
  62. else {System.out.println("不支持的HTTP协议包类型");}//其它的其它类型 暂不支持  
  63. }  
  64. private void getContentlen_Chucked(String tempStr)//获得长度 CONTENT-LENGTH 或 是否为CHUNKED型  
  65. {String ss1="CONTENT-LENGTH:";  
  66. String ss2=new String("TRANSFER-ENCODING: CHUNKED");  
  67. int clIndex= tempStr.indexOf(ss1);  
  68. int chuckIndex = tempStr.indexOf(ss2);//为CHUNKED型  
  69. byte requst[]= tempStr.getBytes();  
  70. if(clIndex!=-1)  
  71. //从clIndex+1起至rn  
  72. StringBuffer sb=new StringBuffer();  
  73. for(int i=(clIndex+16);;i++)  
  74. {if(requst[i]!=(byte)13 && requst[i]!=(byte)10 )  
  75. {sb.append((char)requst[i]);}  
  76. else   
  77. break;}  
  78. CONTENT_LENGTH=Integer.parseInt(sb.toString());//正式的HTML文件的大小  
  79. //System.out.println("CONTENT_LENGTH=="+CONTENT_LENGTH);}  
  80. if(chuckIndex!=-1) beChucked=true;}  
  81. private intgetChuckSize() //Chuck大小{  
  82. byte[]crlf= new byte[1];  
  83. StringBuffersb1= new StringBuffer();  
  84. intcrlfNum= 0;//已经连接的回车换行数 crlfNum=4为头部结束  
  85. try{while(input.read(crlf)!=-1)//读取头部{  
  86. if(crlf[0]==crlf13 || crlf[0]==crlf10)  
  87. {crlfNum++; }  
  88. else 
  89. {crlfNum=0;} //不是则清  
  90. sb1.append((char)crlf[0]);  
  91. request=request.append(new String(crlf,0,1));//byte数组相加  
  92. if(crlfNum==2) break;}  
  93. }catch(IOException e){  
  94. System.out.println("Read Http Package Error!");  
  95. return 0;}  
  96. return Integer.parseInt((sb1.toString()).trim(),16); //16进控制  
  97. }//通过此来进行过滤,是否为发至目标服务器的HTTP协议包  
  98. private String parseUri(String requestString) {   
  99. int index1, index2;  
  100. index1 = requestString.indexOf(' ');  
  101. if (index1 != -1) {  
  102. index2 = requestString.indexOf(' ', index1 + 1);  
  103. if (index2 > index1)  
  104. return requestString.substring(index1 + 1, index2);}  
  105. return null;}  
  106. public String getData() {  
  107. return request.toString();}} 

使用此类:

  1. SocketRequest request = new SocketRequest(socket); //socket为ServerSocket.accept()返回的Socket实例  
  2. request.ReadData();//读取数据  
  3. request.getData(); 

为什么我要用这么大的力量去读取呢,尤其是在因为Socket连接在发送数据时,由于网络的原因经常会发生延迟现象,可能在服务器端开始接收数据时可能只有部分数据可以从InputStream中获得,在一些地方处理不当时,可能只能获得不完整的数据或是错误的数据。

从InputStream读取字节时有多种办法:

常用int read()与int read(byte[] b)。在用read(byte[])时,程序员经常会犯错误,因为在网络环境中,读取的数据量不一定等于参数的大小。

责任编辑:佟健 来源: 网界网
相关推荐

2010-06-29 13:24:26

HTTP协议

2010-06-29 13:18:31

HTTP协议

2020-06-17 21:39:11

HTTP协议服务器

2019-04-08 15:11:12

HTTP协议Web

2010-06-24 13:18:38

ICMP协议

2018-04-17 16:29:24

Java面试HTTP

2019-08-01 15:25:17

Http服务器协议

2014-10-22 09:36:41

TCPIP

2017-05-26 10:35:13

前端HTTP

2021-03-05 11:20:24

HTTPWebshellWeb服务器

2015-10-09 15:07:02

HTTP网络协议

2018-10-18 10:05:43

HTTP网络协议TCP

2015-09-15 13:48:01

网络协议HTTP Client

2010-09-09 13:09:33

协议栈开发

2010-06-23 14:27:04

Fix协议

2010-07-01 16:01:05

HTTP协议

2010-06-08 12:31:15

HTTP协议实体

2022-03-09 18:54:30

HTTP缓存协议cache

2011-09-06 09:48:41

MTK平台

2019-08-23 06:36:32

点赞
收藏

51CTO技术栈公众号