[Java] Java实现http协议解析 →→→→→进入此内容的聊天室

来自 , 2020-06-01, 写在 Java, 查看 127 次.
URL http://www.code666.cn/view/a7d8ae45
  1.    下面的代码片断创建一个与本地HTTP服务器(127.0.0.1代表本地主机的IP地址)通信的Socket,发送一个HTTP请求包,准备接收服务器的应答。
  2.   Socket socket    = new Socket("127.0.0.1", "80");
  3.   OutputStream os  = socket.getOutputStream();
  4.   InputStream  ins = socket.getInputStream();
  5.   sb.append("GET /index.jsp HTTP/1.1\r\n");//注意\r\n为回车换行
  6.   sb.append("Accept-Language: zh-cn\r\n");
  7.   sb.append("Connection: Keep-Alive\r\n");
  8.   sb.append("Host: 192.168.0.106\r\n");
  9.   sb.append("Content-Length: 37\r\n");
  10.   sb.append("\r\n");
  11.   sb.append("userName=new_andy&password=new_andy\r\n");
  12.   sb.append("\r\n");
  13.  
  14.   //向Web服务器发送一个HTTP请求包
  15.   os.write(sb.toString().getBytes());
  16.  
  17.   服务器端的代码在大致结构为:
  18.   while (!shutdown) {
  19.         Socket socket = null;
  20.         try {
  21.             socket = serverSocket.accept(); //等待客户以送HTTP请求包
  22.             // 创建HTTP请求包处理线程
  23.             RequestThread request = new RequestThread(socket);
  24.             request.start();
  25.             if(shutdown) System.exit(0);
  26.         }
  27.         catch (Exception e) {
  28.             e.printStackTrace();
  29.         }
  30.     }
  31.   RequestThread线程分析HTTP请求包,跟根据请求包内容在服务端生成一个HTTP应答包。下一节说明怎样分析HTTP包。
  32.   InputStream  input = socket.getInputStream();  //从此字节数据流获得HTTP请求包内容
  33.     OutputStream output= socket.getOutputStream(); //向此字节流写入HTTP应答包内容
  34.    
  35. 三、读取HTTP包
  36.   以下我自己设计的一个读取HTTP包的类SocketRequest。
  37.   public class SocketRequest {  //从指定的Socket的InputStream中读取数据
  38.   private InputStream  input;
  39.   private String     uri;
  40.   private StringBuffer  request=new StringBuffer();  //用于保存所有内容
  41.   private int       CONTENT_LENGTH=0;  //实际包内容数据长
  42.   private boolean    bePost = false;
  43.   private boolean    beHttpResponse = false;
  44.   private boolean    beChucked = false;
  45.   private boolean    beGet = false;
  46.   private byte       crlf13 = (byte)13; //碶 ?br/>   private byte       crlf10 = (byte)10;  //碶 ?/FONT>
  47.   public SocketRequest(InputStream input) {
  48.     this.input = input;
  49.   }
  50.  public SocketRequest(Socket socket) {
  51.     this.input = socket.getInputStream();
  52.   }
  53.   public void ReadData() {  //解析 获得InputStream的数据
  54.  
  55.   ReadHeader();  //头部
  56.   if(beChucked) //为Chucked
  57.   {
  58.    int ChuckSize=0;
  59.    while((ChuckSize=getChuckSize())>0) //多个Chucked
  60.    {
  61.     readLenData(ChuckSize+2);//读取定长数据
  62.    }
  63.    readLenData(2); //最后的2位
  64.   }
  65.  
  66.   if(CONTENT_LENGTH>0)
  67.   {
  68.    readLenData(CONTENT_LENGTH);//读取定长数据
  69.   }
  70.  
  71.     uri = "";//parseUri(new String(request));
  72.   }
  73.  
  74.   private void readLenData(int size)  //读取定长数据
  75.   {
  76.    int readed=0;  //已经读取数
  77.    try{
  78.     int available=0;//input.available(); //可读数
  79.     if(available>(size-readed)) available=size-readed;
  80.     while( readed<size )
  81.      {
  82.        while(available==0){  //等到有数据可读
  83.          available = input.available(); //可读数
  84.         }
  85.         if(available>(size-readed)) available= size-readed; //size-readed--剩余数
  86.         if(available>2048) available= 2048; //size-readed--剩余数
  87.        byte[] buffer = new byte[available];
  88.        int reading = input.read(buffer);
  89.        request=request.append(new String(buffer,0,reading));  //byte数组相加
  90.         readed+=reading;  //已读字符
  91.    }
  92.    }catch(IOException e){
  93.      System.out.println("Read readLenData Error!");
  94.    }
  95.  }
  96.  
  97.    private void  ReadHeader() //读取头部 并获得大小
  98.    {
  99.     byte[]  crlf   = new byte[1];
  100.    int     crlfNum= 0;   //已经连接的回车换行数 crlfNum=4为头部结束
  101.     try{
  102.      while( input.read(crlf)!=-1 )   //读取头部
  103.      {
  104.       if(crlf[0]==crlf13 || crlf[0]==crlf10)
  105.       {
  106.          crlfNum++;
  107.       }
  108.       else
  109.       {  crlfNum=0;  } //不是则清
  110.       request=request.append(new String(crlf,0,1));  //byte数组相加
  111.       if(crlfNum==4) break;
  112.      }
  113.    }catch(IOException e){
  114.      System.out.println("Read Http Header Error!");
  115.      return;
  116.     }
  117.  
  118.     String tempStr=(new String(request)).toUpperCase();
  119.    
  120.     //这里我只处理了GET与POST方法
  121.     String  strMethod  = tempStr.substring(0,4);
  122.     if(strMethod.equals("GET ")) //前
  123.     {  beGet=true;    
  124.     }
  125.     else if(strMethod.equals("POST"))
  126.     {
  127.      bePost=true;
  128.      getContentlen_Chucked(tempStr);
  129.     }
  130.     else {
  131.      System.out.println("不支持的HTTP包类型");
  132.      
  133.     } //其它的其它类型 暂不支持
  134.   }
  135.   private void getContentlen_Chucked(String tempStr)  //获得长度 CONTENT-LENGTH 或 是否为CHUNKED型
  136.   {
  137.    String ss1="CONTENT-LENGTH:";
  138.    String ss2=new String("TRANSFER-ENCODING: CHUNKED");
  139.    
  140.    int clIndex   = tempStr.indexOf(ss1);
  141.     int chuckIndex = tempStr.indexOf(ss2);  //为CHUNKED型
  142.     byte requst[]= tempStr.getBytes();
  143.     if(clIndex!=-1)
  144.     { //从clIndex+1起至\r\n
  145.        StringBuffer sb=new StringBuffer();
  146.        
  147.        for(int i=(clIndex+16);;i++)
  148.        {
  149.         if(requst[i]!=(byte)13 && requst[i]!=(byte)10 )
  150.         {
  151.           sb.append((char)requst[i]);
  152.         }
  153.         else
  154.          break;
  155.        }
  156.        
  157.        CONTENT_LENGTH=Integer.parseInt(sb.toString());  //正式的HTML文件的大小
  158.        //System.out.println("CONTENT_LENGTH==  "+CONTENT_LENGTH);
  159.    }
  160.    if(chuckIndex!=-1) beChucked=true;
  161.   }
  162.    
  163.   private int  getChuckSize() //Chuck大小
  164.    {
  165.     byte[]  crlf   = new byte[1];
  166.     StringBuffer  sb1   = new StringBuffer();
  167.     int     crlfNum= 0;   //已经连接的回车换行数 crlfNum=4为头部结束
  168.    
  169.     try{
  170.      while(input.read(crlf)!=-1)   //读取头部
  171.      {
  172.       if(crlf[0]==crlf13 || crlf[0]==crlf10)
  173.       {  crlfNum++; }
  174.       else
  175.       {  crlfNum=0;  } //不是则清
  176.       sb1.append((char)crlf[0]);
  177.       request=request.append(new String(crlf,0,1));  //byte数组相加
  178.       if(crlfNum==2) break;
  179.      }
  180.    }catch(IOException e){
  181.      System.out.println("Read Http Package Error!");
  182.      return 0;
  183.     }
  184.  
  185.    return Integer.parseInt((sb1.toString()).trim(),16); //16进控制
  186.  }
  187.   //通过此来进行过滤,是否为发至目标服务器的HTTP包
  188.   private String parseUri(String requestString) {
  189.     int index1, index2;
  190.     index1 = requestString.indexOf(??;
  191.     if (index1 != -1) {
  192.       index2 = requestString.indexOf(?? index1 + 1);
  193.       if (index2 > index1)
  194.         return requestString.substring(index1 + 1, index2);
  195.     }
  196.     return null;
  197.   }
  198.   public String getData() {
  199.     return request.toString();
  200.   }
  201. }
  202.  使用此类:
  203.  SocketRequest request = new SocketRequest(socket); //socket为ServerSocket.accept()返回的Socket实例
  204.  request.ReadData();  //读取数据
  205.  request.getData();
  206.  为什么我要用这么大的力量去读取呢,尤其是在因为Socket连接在发送数据时,由于网络的原因经常会发生延迟现象,可能在服务器端开始接收数据时可能只有部分数据可以从InputStream中获得,在一些地方处理不当时,可能只能获得不完整的数据或是错误的数据。
  207.  从InputStream读取字节时有多种办法:
  208.  常用int read()int read(byte[] b)。在用read(byte[])时,程序员经常会犯错误,因为在网络环境中,读取的数据量不一定等于参数的大小。
  209.  
  210.  希望我的这篇文章能给你带来一些帮助。//源代码片段来自云代码http://yuncode.net
  211.                        

回复 "Java实现http协议解析"

这儿你可以回复上面这条便签

captcha