HTTP协议栈

     一.  HTTP全称是Hyper Transfer protocol ,即超文本传输协议,当今普遍采用版本Http1.1,HTTP协议已属于应用层协议,它构建在TCP之上,处于TCP/IP架构的顶端,为了更好的理解HTTP协议,我们基于javaSocketAPI设计一个简单的应用层通信协议,来窥探协议实现的一些过程与细节。

客户端向服务端发送一条命令,服务端接收到命令后,会判断命令是否为"HELLO",若是则返回客户端"hello!",否则返回客户端"bye bye"

1.协议请求:

 1 package com.zqf.fenbushi;
 2 //协议请求
 3 //2016110758 邹奇方
 4  public class Request {
 5  
 6      /**
 7       * 协议编码 0:GBK;1:UTF-8
 8       */
 9      private byte encode;
10      /**
11       * 命令
12       */
13      private String command;
14      /**
15       * 命令长度
16       */
17      private int commandLength;
18  
19      public byte getEncode() {
20          return encode;
21      }
22  
23      public void setEncode(byte encode) {
24          this.encode = encode;
25      }
26  
27      public String getCommand() {
28          return command;
29      }
30  
31      public void setCommand(String command) {
32          this.command = command;
33      }
34  
35      public int getCommandLength() {
36          return commandLength;
37      }
38  
39      public void setCommandLength(int commandLength) {
40          this.commandLength = commandLength;
41      }
42  
43  }

2.协议响应:

 1 package com.zqf.fenbushi;
 2 //协议响应
 3 //2016110758 邹奇方
 4  public class Response {
 5      /**
 6       * 编码
 7       */
 8      private byte encode;
 9      /**
10       * 响应
11       */
12      private String response;
13      /**
14       * 响应长度
15       */
16      private int responseLength;
17  
18      public byte getEncode() {
19          return encode;
20      }
21  
22      public void setEncode(byte encode) {
23          this.encode = encode;
24      }
25  
26      public String getResponse() {
27          return response;
28      }
29  
30      public void setResponse(String response) {
31          this.response = response;
32      }
33  
34      public int getResponseLength() {
35          return responseLength;
36      }
37  
38      public void setResponseLength(int responseLength) {
39          this.responseLength = responseLength;
40      }
41  
42      @Override
43      public String toString() {
44          return "Response [encode=" + encode + ", response=" + response + ", responseLength=" + responseLength + "]";
45      }
46      
47  }

3.客户端发送,以及服务端响应处理代码:

 1 package com.zqf.fenbushi;
 2 //客服端发送,以及服务端响应处理代码
 3 //2016110758 邹奇方
 4 import java.net.ServerSocket;
 5 import java.net.Socket;
 6 
 7 
 8 public class Server {
 9     public static void main(String[] args) throws Exception{
10         System.out.println("开启服务器...");
11          ServerSocket server = new ServerSocket(16789);
12          while(true) {
13              Socket client = server.accept();
14              //读取请求数据
15              Request request = ProtocolUtil.readRequest(client.getInputStream());
16              //封装响应数据
17              Response response = new Response();
18              System.out.println("response"+response);
19              response.setEncode(Encode.UTF8.getValue());
20              response.setResponse(request.getCommand().equals("HELLO") ? "hello!" : "bye bye");
21              response.setResponseLength(response.getResponse().length());
22              //响应到客户端
23              ProtocolUtil.writeResponse(client.getOutputStream(), response);
24          }
25      }
26  }

4.客户端:

 1 package com.zqf.fenbushi;
 2 //客户端
 3 //2016110758 邹奇方
 4 import java.net.Socket;
 5 
 6 public class Client {
 7      
 8     public static void main(String[] args) throws Exception {
 9         //组装请求数据
10         Request request = new Request();
11         request.setCommand("HELLO");
12         request.setCommandLength(request.getCommand().length());
13         request.setEncode(Encode.UTF8.getValue());
14         Socket client = new Socket("127.0.0.1", 16789);
15         System.out.println(client);
16         
17             
18        //发送请求
19         ProtocolUtil.writeRequest(client.getOutputStream(), request);
20         //读取相应
21         Response response = ProtocolUtil.readResponse(client.getInputStream());
22         System.out.println(response);
23      }
24  }

5.ProtocolUtil 类:

  1 package com.zqf.fenbushi;
  2 
  3 //2016110758 邹奇方
  4 import java.io.InputStream;
  5 import java.io.OutputStream;
  6 
  7 public class ProtocolUtil {
  8      
  9      public static void writeRequest(OutputStream out, Request request) {
 10          try {
 11              out.write(request.getEncode());
 12              //write一个int值会截取其低8位传输,丢弃其高24位,因此需要将基本类型转化为字节流
 13              //java采用Big Endian字节序,而所有的网络协议也都是以Big Endian字节序来进行传输,所以再进行数据的传输和接收时,需要先将数据转化成Big Endian字节序
 14              //out.write(request.getCommandLength());
 15              out.write(int2ByteArray(request.getCommandLength()));
 16              out.write(Encode.GBK.getValue() == request.getEncode() ? request.getCommand().getBytes("GBK") : request.getCommand().getBytes("UTF8"));
 17              out.flush();
 18          } catch (Exception e) {
 19              System.err.println(e.getMessage());
 20          }
 21      }
 22      
 23      /**
 24       * 将响应输出到客户端
 25       * @param os
 26       * @param response
 27       */
 28      public static void writeResponse(OutputStream out, Response response) {
 29          try {
 30              out.write(response.getEncode());
 31              out.write(int2ByteArray(response.getResponseLength()));
 32              out.write(Encode.GBK.getValue() == response.getEncode() ? response.getResponse().getBytes("GBK") : response.getResponse().getBytes("UTF8"));
 33              out.flush();
 34          } catch (Exception e) {
 35              System.err.println(e.getMessage());
 36          }
 37      }
 38      
 39      public static Request readRequest(InputStream is) {
 40          Request request = new Request();
 41          try {
 42              //读取编码
 43              byte [] encodeByte = new byte[1];
 44              is.read(encodeByte);
 45              byte encode = encodeByte[0];
 46              //读取命令长度
 47              byte [] commandLengthByte = new byte[4];//缓冲区
 48              is.read(commandLengthByte);
 49              int commandLength = byte2Int(commandLengthByte);
 50              //读取命令
 51              byte [] commandByte = new byte[commandLength];
 52              is.read(commandByte);
 53              String command = Encode.GBK.getValue() == encode ? new String(commandByte, "GBK") : new String(commandByte, "UTF8");
 54              //组装请求返回
 55              request.setEncode(encode);
 56              request.setCommand(command);
 57              request.setCommandLength(commandLength);
 58          } catch (Exception e) {
 59              System.err.println(e.getMessage());
 60          }
 61          return request;
 62      }
 63      
 64      public static Response readResponse(InputStream is) {
 65          Response response = new Response();
 66          try {
 67              byte [] encodeByte = new byte[1];
 68              is.read(encodeByte);
 69              byte encode = encodeByte[0];
 70              byte [] responseLengthByte = new byte[4];
 71              is.read(responseLengthByte);
 72              int commandLength = byte2Int(responseLengthByte);
 73              byte [] responseByte = new byte[commandLength];
 74              is.read(responseByte);
 75              String resContent = Encode.GBK.getValue() == encode ? new String(responseByte, "GBK") : new String(responseByte, "UTF8");
 76              response.setEncode(encode);
 77              response.setResponse(resContent);
 78              response.setResponseLength(commandLength);
 79          } catch (Exception e) {
 80              System.err.println(e.getMessage());
 81          }
 82          return response;
 83      }
 84      
 85      public static int byte2Int(byte [] bytes) {
 86          int num = bytes[3] & 0xFF;
 87          num |= ((bytes[2] << 8) & 0xFF00);
 88          num |= ((bytes[1] << 16) & 0xFF0000);
 89          num |= ((bytes[0] << 24) & 0xFF000000);
 90          return num;
 91      }
 92      
 93      public static byte[] int2ByteArray(int i) {
 94          byte [] result = new byte[4];
 95          result[0] = (byte) ((i >> 24) & 0xFF);
 96          result[1] = (byte) ((i >> 16) & 0xFF);
 97          result[2] = (byte) ((i >> 8) & 0xFF);
 98          result[3] = (byte) (i & 0xFF);
 99          return result;
100      }
101      
102  }

 

6.Encode类:

 1 package com.zqf.fenbushi;
 2 
 3 //2016110758 邹奇方
 4 public class Encode {
 5     
 6     private  byte enCode;  //编码,取值1表示 utf-8编码,取值0表示 gbk编码
 7     
 8     
 9     public static Encode UTF8 = new Encode("utf-8");
10     public static Encode GBK = new Encode("gbk");
11     
12     public Encode(String enCode){
13         
14         if(enCode.equals("utf-8")){
15             this.enCode = 1;
16         }
17         if(enCode.equals("gbk")){
18             this.enCode = 0;
19         }
20     }
21     
22     public  byte getValue(){
23         
24         return this.enCode;
25         
26     }
27     
28     //测试 
29     public static void main(String[] args) {
30         
31         System.out.println(Encode.UTF8.getValue());
32         System.out.println(Encode.GBK.getValue());
33         
34     }
35     
36 }

以上代码运行结果:(在客服端输入HELLO,则输出hello,输入不是HELLO,则输出为bye bye)

(此输入为HELLO)

(此输入不是HELLO)

  二.HTTP请求与响应

    下图是HTTP请求与响应的过程步骤,在此不详细赘述。

  三.通过HttpClient发送HTTP请求

 

  HttpClientHTTP协议通信的过程进行了封装,下面是简单的通过HttpClient发送HTTP GET请求,并获取服务端响应的代码:

 

 1       //url前加上http协议头,标明该请求为http请求
 2         String url = "https://www.baidu.com";
 3         //组装请求
 4         HttpClient httpClient = new DefaultHttpClient();
 5         HttpGet httpGet = new HttpGet(url);
 6         //接收响应
 7         HttpResponse response = httpClient.execute(httpGet);
 8         HttpEntity entity = response.getEntity();
 9         byte[] byteArray = EntityUtils.toByteArray(entity);
10         String result = new String(byteArray, "utf8");
11         System.out.println(result);

 

  四.使用HTTP协议的优势

  随着请求规模的扩展,基于TCP协议的RPC的实现,需要考虑多线程并发、锁、I/O等复杂的底层细节,在大流量高并发的压力下,任何一个小的错误都可能被无限放大,最终导致程序宕机。而对于基于HTTP协议的实现来说,很多成熟的开源web容易已经帮其处理好了这些事情,如ApacheTomcatJboss等,开发人员可将更多的精力集中在业务实现上,而非处理底层细节。

 

 

 

posted @ 2019-03-07 10:47  齐方  阅读(1424)  评论(1编辑  收藏  举报