对于发送的UDP数据包,要以Byte[]的形式包装为DatagramPacket后发送,接收时解析为Byte[],后解析出具体数据。
之前我的的文章有Netty接收和发送UDP的实现,这里不再赘述。
- 先展示实体类。
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
/**
* @author qs
* 2021.3.16
* 数据包头实体类
* --------------------------------------------------
* 命名 意义 设计长度 Java类型
* pver 协议版本 1Byte byte
* sid 信源标识 4Byte int
* did 信宿标识 4Byte int
* stime 发送时标 6Byte short and int
* dtype 数据类型标识 4Byte int
* dlength 数据体长度 2Byte short
* --------------------------------------------------
*/
@ToString
@Setter
@Getter
public class PackageHeader {
public byte pver;
public int sid;
public int did;
public short stime1;
public int stime2;
public int dtype;
public short dlength;
}
- 包装数据
// 合并两个Byte[]用的
ByteArrayOutputStream os = new ByteArrayOutputStream();
//这里转换,body转换原理一样
byte[] header = Convertor.ObjectToByte(packageHeader);
// byte[] body = Convertor.ObjectToByte(workingConInfo);
byte[] body = Convertor.ObjectToByte(controlInstruInfo);
os.write(header);
os.write(body);
byte[] data = os.toByteArray();
udpClient.bind(6679, "127.0.0.1", 6678, "127.0.0.1")
.send(data);
- 解析数据
import com.dpsm.yk.sbjk.Parser.Dao.ParseControlService;
import com.dpsm.yk.sbjk.Parser.Entity.ControlInstruInfo;
import com.dpsm.yk.sbjk.Parser.Entity.PackageHeader;
import com.dpsm.yk.sbjk.Tools.Util.Convertor;
import com.dpsm.yk.sbjk.Tools.Util.GlobalConstant;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.socket.DatagramPacket;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.ServletContextAware;
import javax.servlet.ServletContext;
import java.util.Arrays;
/**
* 对于新消息进行操作的类
*/
@Log4j2
@Component
public class NettyUDPServerHandler extends SimpleChannelInboundHandler<DatagramPacket> implements ServletContextAware {
private ParseControlService parseControlService;
private static ParseControlService parseControl;
@Autowired
public void setParseControlService(ParseControlService parseControlService) {
this.parseControlService = parseControlService;
}
/**
* 重写接收到的数据的具体操作
*
* @param channelHandlerContext
* @param datagramPacket
* @throws Exception
*/
@Override
protected void channelRead0(ChannelHandlerContext channelHandlerContext, DatagramPacket datagramPacket) throws Exception {
// parseControl.parseControl(datagramPacket.content());
ByteBuf byteBuf = datagramPacket.content();
byte[] bytes = new byte[byteBuf.readableBytes()];
byteBuf.readBytes(bytes);
// 在这里转换为实体类
byte[] header = Arrays.copyOfRange(bytes, 0, GlobalConstant.PACKAGE_HEADER_LENGTH);
PackageHeader packageHeader = Convertor.byteToObject(header, PackageHeader.class);
byte[] body = Arrays.copyOfRange(bytes, GlobalConstant.PACKAGE_HEADER_LENGTH, bytes.length);
ControlInstruInfo controlInstruInfo = Convertor.byteToObject(body, ControlInstruInfo.class);
System.out.println(packageHeader.toString());
System.out.println(controlInstruInfo.toString());
}
/**
* 出错回调
*
* @param channelHandlerContext
* @param cause
* @throws Exception
*/
@Override
public void exceptionCaught(ChannelHandlerContext channelHandlerContext, Throwable cause) throws Exception {
cause.printStackTrace();
channelHandlerContext.close();
}
@Override
public void setServletContext(ServletContext servletContext) {
parseControl = this.parseControlService;
}
}
- 来看Convertor类实现,用反射实现的。
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import java.lang.reflect.Field;
import java.nio.charset.Charset;
import java.time.LocalDateTime;
import java.util.*;
/**
* 用来进行数据转换的类
*
* @author qs
* 2021.3.16
*/
public class Convertor {
/**
* 字节数组向对象进行转化
*
* @param bytes 输入的byte数组
* @param clazz 需要创建的对象类
* @param <T> 泛型
* @return 转换后的对象
*/
public static <T> T byteToObject(byte[] bytes, Class<T> clazz) {
T instance = null;
try {
instance = clazz.newInstance();
} catch (Exception e) {
throw new RuntimeException("实例化类失败", e);
}
List<Field> fields = new ArrayList<>();
getFields(clazz, fields);
ByteBuf buffer = Unpooled.buffer().writeBytes(bytes);
for (Field field : fields) {
fillData(field, instance, buffer);
}
return instance;
}
/**
* 获取对象的变量
*
* @param clazz 类
* @param list 变量存储列表
* @return 变量列表
*/
private static List<Field> getFields(Class clazz, List list) {
Field[] fields = clazz.getDeclaredFields();
list.addAll(Arrays.asList(fields));
Class clazzSuper = clazz.getSuperclass();
if (clazzSuper != null)
getFields(clazzSuper, list);
return list;
}
/**
* 通过类型赋值
*
* @param field 属性
* @param instance 对象
* @param buffer 数据
*/
private static void fillData(Field field, Object instance, ByteBuf buffer) {
field.setAccessible(true);
String typeName = field.getType().getName();
try {
switch (typeName) {
case "java.lang.Boolean":
case "boolean":
boolean b = buffer.readBoolean();
field.set(instance, b);
break;
case "java.lang.Character":
case "char":
CharSequence charSequence = buffer.readCharSequence(2, Charset.forName("UTF-8"));
field.set(instance, charSequence);
break;
case "java.lang.Byte":
case "byte":
byte b1 = buffer.readByte();
field.set(instance, b1);
break;
case "java.lang.Short":
case "short":
short readShort = buffer.readShort();
field.set(instance, readShort);
break;
case "java.lang.Integer":
case "int":
int readInt = buffer.readInt();
field.set(instance, readInt);
break;
case "java.lang.Long":
case "long":
long l = buffer.readLong();
field.set(instance, l);
break;
case "java.lang.Float":
case "float":
float readFloat = buffer.readFloat();
field.set(instance, readFloat);
break;
case "java.lang.Double":
case "double":
double readDouble = buffer.readDouble();
field.set(instance, readDouble);
break;
case "java.util.Map":
Map<Byte, Byte> map = new HashMap<>();
while (true) {
try {
byte aByte = buffer.readByte();
byte aByte1 = buffer.readByte();
map.put(aByte, aByte1);
} catch (Exception e) {
field.set(instance, map);
break;
}
}
break;
case "java.util.List":
List<Long> list = new ArrayList<>();
while (true) {
try {
long param = buffer.readLong();
list.add(param);
} catch (Exception e) {
field.set(instance, list);
break;
}
}
break;
default:
Object o = field.getType().newInstance();
for (Field fieldSub : field.getType().getDeclaredFields()) {
fillData(fieldSub, o, buffer);
}
field.set(instance, o);
break;
}
} catch (Exception e) {
throw new RuntimeException(typeName + "读取失败,field:" + field.getName(), e);
}
}
/**
* 对象转ByteBuf
*
* @param o 要转换的对象
* @param <T> 类型
* @return 转换结果
*/
public static <T> byte[] ObjectToByte(T o) {
List<Field> fields = new ArrayList<>();
getFields(o.getClass(), fields);
ByteBuf byteBuf = Unpooled.buffer();
for (Field field : fields) {
write2ByteBuf(field, o, byteBuf);
}
byte[] bytes = new byte[byteBuf.readableBytes()];
byteBuf.readBytes(bytes);
return bytes;
}
/**
* 为ByteBuf赋值
*
* @param field 属性
* @param instance 对象
* @param buffer buffer
*/
private static void write2ByteBuf(Field field, Object instance, ByteBuf buffer) {
field.setAccessible(true);
String typeName = field.getType().getName();
Object value = null;
try {
value = field.get(instance);
} catch (IllegalAccessException e) {
new RuntimeException("反射获取值失败,filed:" + field.getName(), e);
}
if (value == null)
return;
switch (typeName) {
case "java.lang.Boolean":
case "boolean":
buffer.writeBoolean((Boolean) value);
break;
case "java.lang.Character":
case "char":
buffer.writeCharSequence((CharSequence) value, Charset.forName("UTF-8"));
break;
case "java.lang.Byte":
case "byte":
buffer.writeByte((byte) value);
break;
case "java.lang.Short":
case "short":
buffer.writeShort((short) value);
break;
case "java.lang.Integer":
case "int":
buffer.writeInt((int) value);
break;
case "java.lang.Long":
case "long":
buffer.writeLong((long) value);
break;
case "java.lang.Float":
case "float":
buffer.writeFloat((float) value);
break;
case "java.lang.Double":
case "double":
buffer.writeDouble((double) value);
break;
case "java.lang.String":
buffer.writeCharSequence((CharSequence) value, Charset.forName("UTF-8"));
break;
case "java.time.LocalDateTime":
String s = ((LocalDateTime) value).toString();
buffer.writeCharSequence((CharSequence) s, Charset.forName("UTF-8"));
break;
case "java.util.Map":
try {
Map<Byte, Byte> map = (Map<Byte, Byte>) value;
for (byte key : map.keySet()) {
buffer.writeByte(key);
buffer.writeByte(map.get(key));
}
} catch (Exception e) {
e.printStackTrace();
}
break;
case "java.util.List":
try {
List<Long> list = (List<Long>) value;
for (long param : list) {
buffer.writeLong(param);
}
} catch (Exception e) {
e.printStackTrace();
}
break;
default:
for (Field fieldSub : field.getType().getDeclaredFields()) {
write2ByteBuf(fieldSub, value, buffer);
}
break;
}
}
}
- 输出
PackageHeader(pver=1, sid=1024, did=1007, stime1=2, stime2=222, dtype=777, dlength=22)
- 完事.