当前位置:首页 > 编程笔记 > 正文
已解决

对于构建自定义协议的思考(Java)

来自网友在路上 149849提问 提问时间:2023-10-26 15:22:05阅读次数: 49

最佳答案 问答题库498位专家为你答疑解惑

工作转眼也1年时间了,回顾历程,协议占了绝大多数
在这里插入图片描述

JSON(比较常见的通信文本了),protoBuf(小编有写过教程),自定义协议(字节拼接,在一些iot领域中的标准几乎都是字节拼接),当然还有很多其他的但是我不会,还有通过asn完成协议(没接触过)
对于JSON和protoBuf来说,相对简单,因为有现成的库调用JSON,protoBuf编译器;
而对于字节拼接的话可能比较复杂,或者说本来不复杂,但是协议复杂,拼接就复杂了;

而拼接字节形式的协议,又涉及到大端小端模式(大端模式是低位字节排放在内存的低地址端,高位字节排放在内存的高地址端;而小端模式是高位字节排放在内存的低地址端,低位字节排放在内存的高地址端)
简单说明就是:大端是将一个数直接转成bytes数组;而小端则需要对数组进行reverse反转操作后的数组;

假设有这样的一个协议:(下面以大端为例子)
协议头:

消息名称占用字节数消息头1消息类型1消息版本1消息时间戳8消息体1+15*n

协议内容:

消息名称占用字节数感知物体数量1感知物体列表15*n

感知物体对象:

消息名称占用字节数感知物体id1感知物速度4感知物航向角2感知物经度4感知物纬度4

那么我在Java中将构建这样几个对象用来实现协议:
结构:
在这里插入图片描述
实体上层接口规范:Protocol

public abstract class Protocol {byte[] bytes = new byte[0];//抽象出来的bytes数组,用于存储继承者的最终字节void toBytes() {//抽象出来的方法,约束子类必须实现}
}

消息头:

@Data
public class ProtocolHead<T extends Protocol> extends Protocol {private byte msgHead;private byte msgType;private byte msgVersion;private long timeStamp;private T msgBody;@Overridepublic void toBytes() {msgBody.toBytes();//将msgBody 字节数组化ByteBuffer buffer = ByteBuffer.allocate(1 + 1 + 1 + 8 + msgBody.bytes.length);buffer.put(msgHead);buffer.put(msgType);buffer.put(msgVersion);buffer.putLong(timeStamp);buffer.put(msgBody.bytes);bytes = buffer.array();}
}

消息体:

@Data
public class ProtocolBody extends Protocol {private byte perNum;private PerceptionData[] perceptionDataArr;@Overridepublic void toBytes() {int size = 1;for (byte i = 0; i < perNum; i++) {perceptionDataArr[i].toBytes();//将每一个感知对象 字节化size += perceptionDataArr[i].bytes.length;}ByteBuffer buffer = ByteBuffer.allocate(size);for (byte i = 0; i < perNum; i++) {buffer.put(perceptionDataArr[i].bytes);}bytes=buffer.array();}
}

消息内容:

@Data
public class PerceptionData extends Protocol {private byte id;private int speed;private short heading;private int lon;private int lat;@Overridepublic void toBytes() {ByteBuffer buffer = ByteBuffer.allocate(1 + 4 + 2 + 4 + 4);buffer.put(id);buffer.putInt(speed);buffer.putShort(heading);buffer.putInt(lon);buffer.putInt(lat);bytes= buffer.array();}
}

输入数据(模拟设备传入的数据)

@Data
public class InputPerData {private long timeStamp;private List<Per> perList;@Datapublic static class Per {private byte id;private int speed;private short heading;private int lon;private int lat;}
}

解析类 convert 转换:

public class EncodeParser {public byte[] convertData(InputPerData inputPerData) {PerceptionData[] perArr = new PerceptionData[inputPerData.getPerList().size()];for (int i = 0; i < inputPerData.getPerList().size(); i++) {InputPerData.Per inputPer = inputPerData.getPerList().get(i);perArr[i] = new PerceptionData();perArr[i].setId(inputPer.getId());perArr[i].setSpeed(inputPer.getSpeed());perArr[i].setHeading(inputPer.getHeading());perArr[i].setLon(inputPer.getLon());perArr[i].setLat(inputPer.getLat());}ProtocolBody body = new ProtocolBody();body.setPerNum((byte) inputPerData.getPerList().size());body.setPerceptionDataArr(perArr);ProtocolHead<ProtocolBody> head = new ProtocolHead<>();head.setMsgHead((byte) 0x01);head.setMsgType((byte) 0x04);head.setMsgVersion((byte) 0x01);head.setTimeStamp(inputPerData.getTimeStamp());head.setMsgBody(body);head.toBytes();//调用编码方法return head.bytes;}public static void main(String[] args) {InputPerData.Per per = new InputPerData.Per();per.setId((byte) 1);per.setSpeed(11);per.setHeading((short) 180);per.setLon(111342345);per.setLat(260099888);InputPerData.Per per1 = new InputPerData.Per();per1.setId((byte) 2);per1.setSpeed(10);per1.setHeading((short) 120);per1.setLon(114909989);per1.setLat(269894903);EncodeParser parser = new EncodeParser();InputPerData input = new InputPerData();input.setTimeStamp(System.currentTimeMillis());input.setPerList(Lists.newArrayList(per, per1));byte[] bytes = parser.convertData(input);//最终byte用于网络通信,常见于 netty的tcp/udp通信System.out.println("bytes = " + Arrays.toString(bytes));}}

感觉这样能减少在代码内部的侵入计算,编写自定义协议也更加方便;
文章有不足的地方还望指正,小子修改
当然大佬们有什么更好的方法,可以沟通交流一下

查看全文

99%的人还看了

猜你感兴趣

版权申明

本文"对于构建自定义协议的思考(Java)":http://eshow365.cn/6-25174-0.html 内容来自互联网,请自行判断内容的正确性。如有侵权请联系我们,立即删除!