使用 Java 类 实现Http协议
Java 实现Http协议
HTTP协议属于应用层协议,它构建于TCP和IP协议之上,处于TCP/IP协议架构层的顶端,所以,它不用处理下层协议间诸如丢包补发、握手及数据的分段及重新组装等繁琐的细节,使开发人员可以专注于应用业务。
协议是通信的规范,为了更好的理解HTTP协议,我们可以基于Java的Socket API接口,通过设计一个简单的应用层通信协议,来简单分析下协议实现的过程和细节。
在我们今天的示例程序中,客户端会向服务端发送一条命令,服务端在接收到命令后,会判断命令是否是“HELLO”,如果是“HELLO”, 则服务端返回给客户端的响应为“hello”,否则,服务端返回给客户端的响应为“bye bye”。
我们接下来用Java实现这个简单的应用层通信协议,
一、协议请求的定义
协议的请求主要包括:编码、命令和命令长度三个字段。
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 + "]"; } }
二、响应协议的定义
协议的响应主要包括:编码、响应内容和响应长度三个字段。
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两种编码。
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对象。
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”信息。
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工具类的实现
ProtocolUtils
的readRequest
方法将从传递进来的输入流中读取请求的encode
、command
和commandLength
三个参数,进行相应的编码转化,构造成Request
对象返回。而writeResponse
方法则是将response
对象的字段根据对应的编码写入到响应的输出流中。
有一个细节需要重点注意:OutputStream
中直接写入一个int类型,会截取其低8位,丢弃其高24位,所以,在传递和接收数据时,需要进行相应的转化操作。
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类的实现
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语言实现经典《复杂迷宫》游戏,文中采用了swing技术进行了界面化处理,感兴趣的小伙伴可以动手试一试...2022-02-01
java 运行报错has been compiled by a more recent version of the Java Runtime
java 运行报错has been compiled by a more recent version of the Java Runtime (class file version 54.0)...2021-04-01- 这篇文章主要介绍了在java中获取List集合中最大的日期时间操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-08-15
- 这篇文章主要介绍了教你怎么用Java获取国家法定节假日,文中有非常详细的代码示例,对正在学习java的小伙伴们有非常好的帮助,需要的朋友可以参考下...2021-04-23
- 这篇文章主要介绍了Java如何发起http请求的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-03-31
- 说起C#和Java这两门语言(语法,数据类型 等),个人以为,大概有90%以上的相似,甚至可以认为几乎一样。但是在工作中,我也发现了一些细微的差别...2020-06-25
- 这篇文章主要介绍了解决Java处理HTTP请求超时的问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-03-29
- 这篇文章主要介绍了java 判断两个时间段是否重叠的案例,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-08-15
- 这篇文章主要介绍了超简洁java实现双色球若干注随机号码生成(实例代码),本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2021-04-02
- 这篇文章主要介绍了Java生成随机姓名、性别和年龄的实现示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-10-01
java 画pdf用itext调整表格宽度、自定义各个列宽的方法
这篇文章主要介绍了java 画pdf用itext调整表格宽度、自定义各个列宽的方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-01-31- 这篇文章主要介绍了java正则表达式判断前端参数修改表中另一个字段的值,需要的朋友可以参考下...2021-05-07
Java使用ScriptEngine动态执行代码(附Java几种动态执行代码比较)
这篇文章主要介绍了Java使用ScriptEngine动态执行代码,并且分享Java几种动态执行代码比较,需要的朋友可以参考下...2021-04-15- 这篇文章主要介绍了Java开发实现人机猜拳游戏,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2020-08-03
Java 8 Stream 的终极技巧——Collectors 功能与操作方法详解
这篇文章主要介绍了Java 8 Stream Collectors 功能与操作方法,结合实例形式详细分析了Java 8 Stream Collectors 功能、操作方法及相关注意事项,需要的朋友可以参考下...2020-05-20- 这篇文章主要介绍了Java List集合返回值去掉中括号('[ ]')的操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-08-29
Java中lombok的@Builder注解的解析与简单使用详解
这篇文章主要介绍了Java中lombok的@Builder注解的解析与简单使用,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2021-01-06- 下面小编就为大家带来一篇java中String类型变量的赋值问题介绍。小编觉得挺不错的。现在分享给大家,给大家一个参考。...2016-03-28
- 这篇文章主要介绍了Java线程池中的各个参数如何合理设置操作,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教...2021-06-19
- 在Java中,我们可以利用多线程来最大化地压榨CPU多核计算的能力,下面这篇文章主要给大家介绍了关于java中多线程与线程池基本使用的相关资料,需要的朋友可以参考下...2021-09-13