半小时实现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对象的字段根据对应的编码写入到响应的输出流中。

Kafka进阶篇知识点

image

Kafka高级篇知识点

image

44个Kafka知识点(基础+进阶+高级)解析如下

image

由于篇幅有限,小编已将上面介绍的**《Kafka源码解析与实战》、Kafka面试专题解析、复习学习必备44个Kafka知识点(基础+进阶+高级)都整理成册,全部都是PDF文档**

colUtils.writeResponse(out, response);

}

}

}

ProtocolUtils工具类的实现

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

Kafka进阶篇知识点

[外链图片转存中…(img-VxnDUTeL-1714189210474)]

Kafka高级篇知识点

[外链图片转存中…(img-YnruVv86-1714189210475)]

44个Kafka知识点(基础+进阶+高级)解析如下

[外链图片转存中…(img-NZ36OJbI-1714189210475)]

由于篇幅有限,小编已将上面介绍的**《Kafka源码解析与实战》、Kafka面试专题解析、复习学习必备44个Kafka知识点(基础+进阶+高级)都整理成册,全部都是PDF文档**

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

  • 18
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是Java实现SNTP协议的完整源码,包括网络通信、数据解析和时间计算等功能: ``` import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; public class SNTPClient { private static final int NTP_PACKET_SIZE = 48; private static final int NTP_PORT = 123; private static final int TIMEOUT = 10000; private static final byte[] NTP_PACKET = new byte[NTP_PACKET_SIZE]; static { NTP_PACKET[0] = 0b11100011; // LI, Version, Mode NTP_PACKET[1] = 0; // Stratum level of the local clock NTP_PACKET[2] = 6; // Polling Interval NTP_PACKET[3] = 0xEC; // Peer Clock Precision // 8 bytes of zero for Root Delay & Root Dispersion for (int i = 4; i < 12; i++) { NTP_PACKET[i] = 0; } // 4 bytes of arbitrary data for (int i = 12; i < NTP_PACKET_SIZE; i++) { NTP_PACKET[i] = (byte) (Math.random() * 256); } } public static void main(String[] args) { try { InetAddress address = InetAddress.getByName(args[0]); DatagramPacket requestPacket = new DatagramPacket(NTP_PACKET, NTP_PACKET.length, address, NTP_PORT); DatagramSocket socket = new DatagramSocket(); socket.setSoTimeout(TIMEOUT); socket.send(requestPacket); DatagramPacket responsePacket = new DatagramPacket(new byte[NTP_PACKET_SIZE], NTP_PACKET_SIZE); socket.receive(responsePacket); long localTime = System.currentTimeMillis(); long receiveTime = readTimestamp(responsePacket.getData(), 32); long transmitTime = readTimestamp(responsePacket.getData(), 40); long roundTripTime = localTime - receiveTime; long clockOffset = (receiveTime - transmitTime + roundTripTime) / 2; System.out.println("Local Time: " + localTime); System.out.println("Server Time: " + (transmitTime + clockOffset)); System.out.println("Round Trip Time: " + roundTripTime); System.out.println("Clock Offset: " + clockOffset); socket.close(); } catch (IOException e) { e.printStackTrace(); } } private static long readTimestamp(byte[] data, int offset) { long seconds = 0; long fraction = 0; for (int i = 0; i < 4; i++) { seconds = (seconds << 8) | (data[offset + i] & 0xFF); } for (int i = 4; i < 8; i++) { fraction = (fraction << 8) | (data[offset + i] & 0xFF); } return (seconds * 1000) + ((fraction * 1000L) / 0x100000000L); } } ``` 使用时,可以在命令行中输入以下命令: ``` java SNTPClient <服务器地址> ``` 例如: ``` java SNTPClient time.google.com ``` 程序会向指定的SNTP服务器发送请求,计算本地时间与服务器时间之间的差值,并输出结果。需要注意的是,SNTP协议使用UDP协议进行通信,因此可能会存在丢包或延迟较大的情况。为了避免程序长时间等待,可以通过设置socket的超时时间来限制等待时间,如上述代码中的TIMEOUT变量。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值