服务器之家:专注于服务器技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - Java教程 - 使用 Java 类 实现Http协议

使用 Java 类 实现Http协议

2021-12-21 13:43冰 河 Java教程

这篇文章主要介绍了用几个Java类简单的实现了Http协议相关资料,感兴趣的的朋友可以参考下面具体的文章内容

Java 实现Http协议

HTTP协议属于应用层协议,它构建于TCP和IP协议之上,处于TCP/IP协议架构层的顶端,所以,它不用处理下层协议间诸如丢包补发、握手及数据的分段及重新组装等繁琐的细节,使开发人员可以专注于应用业务。

协议是通信的规范,为了更好的理解HTTP协议,我们可以基于Java的Socket API接口,通过设计一个简单的应用层通信协议,来简单分析下协议实现的过程和细节。

在我们今天的示例程序中,客户端会向服务端发送一条命令,服务端在接收到命令后,会判断命令是否是“HELLO”,如果是“HELLO”, 则服务端返回给客户端的响应为“hello”,否则,服务端返回给客户端的响应为“bye bye”。

我们接下来用Java实现这个简单的应用层通信协议,

使用 Java 类 实现Http协议

一、协议请求的定义

协议的请求主要包括:编码、命令和命令长度三个字段。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
package com.binghe.params;
/**
 * 协议请求的定义
 * @author binghe
 *
 */
public class Request {
 /**
  * 协议编码
  */
 private byte encode;
 
 /**
  * 命令
  */
 private String command;
 
 /**
  * 命令长度
  */
 private int commandLength;
 
 public Request() {
  super();
 }
 
 public Request(byte encode, String command, int commandLength) {
  super();
  this.encode = encode;
  this.command = command;
  this.commandLength = commandLength;
 }
 
 public byte getEncode() {
  return encode;
 }
 
 public void setEncode(byte encode) {
  this.encode = encode;
 }
 
 public String getCommand() {
  return command;
 }
 
 public void setCommand(String command) {
  this.command = command;
 }
 
 public int getCommandLength() {
  return commandLength;
 }
 
 public void setCommandLength(int commandLength) {
  this.commandLength = commandLength;
 }
 
 @Override
 public String toString() {
  return "Request [encode=" + encode + ", command=" + command
    + ", commandLength=" + commandLength + "]";
 }
 
}

二、响应协议的定义

协议的响应主要包括:编码、响应内容和响应长度三个字段。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
package com.binghe.params;
 
/**
 * 协议响应的定义
 * @author binghe
 *
 */
public class Response {
 /**
  * 编码
  */
 private byte encode;
 
 /**
  * 响应内容
  */
 private String response;
 
 /**
  * 响应长度
  */
 private int responseLength;
 
 public Response() {
  super();
 }
 
 public Response(byte encode, String response, int responseLength) {
  super();
  this.encode = encode;
  this.response = response;
  this.responseLength = responseLength;
 }
 
 public byte getEncode() {
  return encode;
 }
 
 public void setEncode(byte encode) {
  this.encode = encode;
 }
 
 public String getResponse() {
  return response;
 }
 
 public void setResponse(String response) {
  this.response = response;
 }
 
 public int getResponseLength() {
  return responseLength;
 }
 
 public void setResponseLength(int responseLength) {
  this.responseLength = responseLength;
 }
 
 @Override
 public String toString() {
  return "Response [encode=" + encode + ", response=" + response
    + ", responseLength=" + responseLength + "]";
 }
 
}

三、编码常量定义

编码常量的定义主要包括UTF-8和GBK两种编码。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
package com.binghe.constant;
 
/**
 * 常量类
 * @author binghe
 *
 */
public final class Encode {
 //UTF-8编码
 public static final byte UTF8 = 1;
 //GBK编码
 public static final byte GBK = 2;
}

四、客户端的实现

客户端先构造一个request请求,通过Socket接口将其发送到远端,并接收远端的响应信息,并构造成一个Response对象。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
package com.binghe.protocol.client;
 
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
 
import com.binghe.constant.Encode;
import com.binghe.params.Request;
import com.binghe.params.Response;
import com.binghe.utils.ProtocolUtils;
 
/**
 * 客户端代码
 * @author binghe
 *
 */
public final class Client {
 public static void main(String[] args) throws IOException{
  //请求
  Request request = new Request();
  request.setCommand("HELLO");
  request.setCommandLength(request.getCommand().length());
  request.setEncode(Encode.UTF8);
  
  Socket client = new Socket("127.0.0.1", 4567);
  OutputStream out = client.getOutputStream();
  
  //发送请求
  ProtocolUtils.writeRequest(out, request);
  
  //读取响应数据
  InputStream in = client.getInputStream();
  Response response = ProtocolUtils.readResponse(in);
  System.out.println("获取的响应结果信息为: " + response.toString());
 }
}

五、服务端的实现

服务端接收客户端的请求,根据接收命令的不同,响应不同的消息信息,如果是“HELLO”命令,则响应“hello”信息,否则响应“bye bye”信息。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
package com.binghe.protocol.server;
 
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
 
import com.binghe.constant.Encode;
import com.binghe.params.Request;
import com.binghe.params.Response;
import com.binghe.utils.ProtocolUtils;
 
/**
 * Server端代码
 * @author binghe
 *
 */
public final class Server {
 public static void main(String[] args) throws IOException{
  ServerSocket server = new ServerSocket(4567);
  while (true) {
   Socket client = server.accept();
   //读取请求数据
   InputStream input = client.getInputStream();
   Request request = ProtocolUtils.readRequest(input);
   System.out.println("收到的请求参数为: " + request.toString());
   OutputStream out = client.getOutputStream();
   //组装响应数据
   Response response = new Response();
   response.setEncode(Encode.UTF8);
   if("HELLO".equals(request.getCommand())){
    response.setResponse("hello");
   }else{
    response.setResponse("bye bye");
   }
   response.setResponseLength(response.getResponse().length());
   ProtocolUtils.writeResponse(out, response);
  }
 }
}

六、ProtocolUtils工具类的实现

ProtocolUtilsreadRequest方法将从传递进来的输入流中读取请求的encodecommandcommandLength三个参数,进行相应的编码转化,构造成Request对象返回。而writeResponse方法则是将response对象的字段根据对应的编码写入到响应的输出流中。

有一个细节需要重点注意:OutputStream中直接写入一个int类型,会截取其低8位,丢弃其高24位,所以,在传递和接收数据时,需要进行相应的转化操作。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
package com.binghe.utils;
 
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
 
import com.binghe.constant.Encode;
import com.binghe.params.Request;
import com.binghe.params.Response;
 
/**
 * 协议工具类
 * @author binghe
 *
 */
public final class ProtocolUtils {
 /**
  * 从输入流中反序列化Request对象
  * @param input
  * @return
  * @throws IOException
  */
 public static Request readRequest(InputStream input) throws IOException{
  //读取编码
  byte[] encodeByte = new byte[1];
  input.read(encodeByte);
  byte encode = encodeByte[0];
  
  //读取命令长度
  byte[] commandLengthBytes = new byte[4];
  input.read(commandLengthBytes);
  int commandLength = ByteUtils.byte2Int(commandLengthBytes);
  
  //读取命令
  byte[] commandBytes = new byte[commandLength];
  input.read(commandBytes);
  String command = "";
  if(Encode.UTF8 == encode){
   command = new String(commandBytes, "UTF-8");
  }else if(Encode.GBK == encode){
   command = new String(commandBytes, "GBK");
  }
  //组装请求返回
  Request request = new Request(encode, command, commandLength);
  return request;
 }
 /**
  * 从输入流中反序列化Response对象
  * @param input
  * @return
  * @throws IOException
  */
 public static Response readResponse(InputStream input) throws IOException{
  //读取编码
  byte[] encodeByte = new byte[1];
  input.read(encodeByte);
  byte encode = encodeByte[0];
  
  //读取响应长度
  byte[] responseLengthBytes = new byte[4];
  input.read(responseLengthBytes);
  int responseLength = ByteUtils.byte2Int(responseLengthBytes);
  
  //读取命令
  byte[] responseBytes = new byte[responseLength];
  input.read(responseBytes);
  String response = "";
  if(Encode.UTF8 == encode){
   response = new String(responseBytes, "UTF-8");
  }else if(Encode.GBK == encode){
   response = new String(responseBytes, "GBK");
  }
  //组装请求返回
  Response resp = new Response(encode, response, responseLength);
  return resp;
 }
 
 /**
  * 序列化请求信息
  * @param output
  * @param response
  */
 public static void writeRequest(OutputStream output, Request request) throws IOException{
  //将response响应返回给客户端
  output.write(request.getEncode());
  //output.write(response.getResponseLength());直接write一个int类型会截取低8位传输丢弃高24位
  output.write(ByteUtils.int2ByteArray(request.getCommandLength()));
  if(Encode.UTF8 == request.getEncode()){
   output.write(request.getCommand().getBytes("UTF-8"));
  }else if(Encode.GBK == request.getEncode()){
   output.write(request.getCommand().getBytes("GBK"));
  }
  output.flush();
 }
 /**
  * 序列化响应信息
  * @param output
  * @param response
  */
 public static void writeResponse(OutputStream output, Response response) throws IOException{
  //将response响应返回给客户端
  output.write(response.getEncode());
  //output.write(response.getResponseLength());直接write一个int类型会截取低8位传输丢弃高24位
  output.write(ByteUtils.int2ByteArray(response.getResponseLength()));
  if(Encode.UTF8 == response.getEncode()){
   output.write(response.getResponse().getBytes("UTF-8"));
  }else if(Encode.GBK == response.getEncode()){
   output.write(response.getResponse().getBytes("GBK"));
  }
  output.flush();
 }
}

七、ByteUtils类的实现

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
package com.binghe.utils;
 
/**
 * 字节转化工具类
 * @author binghe
 *
 */
public final class ByteUtils {
 /**
  * 将byte数组转化为int数字
  * @param bytes
  * @return
  */
 public static int byte2Int(byte[] bytes){
  int num = bytes[3] & 0xFF;
  num |= ((bytes[2] << 8) & 0xFF00);
  num |= ((bytes[1] << 16) & 0xFF0000);
  num |= ((bytes[0] << 24) & 0xFF000000);
  return num;
 }
 
 /**
  * 将int类型数字转化为byte数组
  * @param num
  * @return
  */
 public static byte[] int2ByteArray(int i){
  byte[] result = new byte[4];
  result[0]  = (byte)(( i >> 24 ) & 0xFF);
  result[1]  = (byte)(( i >> 16 ) & 0xFF);
  result[2]  = (byte)(( i >> 8 ) & 0xFF);
  result[3]  = (byte)(i & 0xFF);
  return result;
 }
}

到此这篇关于关于Java 实现Http协议详细内容的文章就介绍到这了,更多相关Java 实现Http协议内容请搜索服务器之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持服务器之家!

使用 Java 类 实现Http协议

原文链接:https://blog.csdn.net/l1028386804/article/details/117154518

延伸 · 阅读

精彩推荐
  • Java教程Guava - 并行编程Futures详解

    Guava - 并行编程Futures详解

    这篇文章主要介绍了Guava - 并行编程Futures详解方法的相关资料,需要的朋友可以参考下...

    破狼6642020-06-15
  • Java教程Java内存模型知识汇总

    Java内存模型知识汇总

    本文中,有很多定义和说法,都是笔者自己理解后定义出来的。希望能够让读者可以对Java内存模型有更加清晰的认识。当然,如有偏颇,欢迎指正。...

    Spring资料11562021-06-01
  • Java教程java实现文本文件删除空行的示例分享

    java实现文本文件删除空行的示例分享

    这篇文章主要介绍了java实现文本文件删除空行的示例,需要的朋友可以参考下 ...

    java教程网4442019-11-17
  • Java教程Mybatis中自定义TypeHandler处理枚举详解

    Mybatis中自定义TypeHandler处理枚举详解

    本文主要介绍了Mybatis中自定义TypeHandler处理枚举的相关知识。具有很好的参考价值,下面跟着小编一起来看下吧 ...

    南轲梦3652020-08-14
  • Java教程Spring的自动装配Bean的三种方式

    Spring的自动装配Bean的三种方式

    本篇文章主要介绍了 Spring的自动装配Bean的三种方式,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧...

    漏断人初静10422020-08-20
  • Java教程用java实现杨辉三角的示例代码

    用java实现杨辉三角的示例代码

    本篇文章主要介绍了用java实现杨辉三角的示例代码,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧...

    白昼黯淡了星光4112021-03-17
  • Java教程深入理解JDK动态代理

    深入理解JDK动态代理

    动态代理的优势是实现无侵入式的代码扩展,做方法的增强;让你可以在不用修改源码的情况下,增强一些方法;在方法的前后你可以做你任何想做的事情(甚...

    安琪拉的博客8252021-04-22
  • Java教程详解SpringBoot配置连接池

    详解SpringBoot配置连接池

    本篇文章主要详解SpringBoot配置连接池,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧 ...

    等风de帆3212020-09-13