瀏覽代碼

TCP协议, 客户端,服务端实现, 按照协商规则接收和发送消息

wanggaokun 1 年之前
父節點
當前提交
a316e1b073

+ 31 - 7
PHM-admin/phm-manage/src/main/java/com/phm/manage/domain/common/OrderXmlVO.java

@@ -3,32 +3,56 @@ package com.phm.manage.domain.common;
 import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
 import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
 import lombok.Data;
+import lombok.Getter;
+
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
 
 /**
  * @author wgk
  */
-@Data
-@JacksonXmlRootElement(localName = "ORDER")
+@Getter
+@XmlRootElement(name = "root")
 public class OrderXmlVO {
     /**
      * 指令类型
      */
-    @JacksonXmlProperty(localName = "ORDER-TYPE")
     private String orderType;
 
     // 指令名称
-    @JacksonXmlProperty(localName = "ORDER-NAME")
     private String orderName;
 
     // 模型
-    @JacksonXmlProperty(localName = "MODEL-TYPE")
     private String model;
 
     // 架次号
-    @JacksonXmlProperty(localName = "SORTIE-NO")
     private String sortieNo;
 
     // 步长
-    @JacksonXmlProperty(localName = "STEP")
     private String step;
+
+    @XmlElement(name = "orderType")
+    public void setOrderType(String orderType) {
+        this.orderType = orderType;
+    }
+
+    @XmlElement(name = "orderName")
+    public void setOrderName(String orderName) {
+        this.orderName = orderName;
+    }
+
+    @XmlElement(name = "model")
+    public void setModel(String model) {
+        this.model = model;
+    }
+
+    @XmlElement(name = "sortieNo")
+    public void setSortieNo(String sortieNo) {
+        this.sortieNo = sortieNo;
+    }
+
+    @XmlElement(name = "step")
+    public void setStep(String step) {
+        this.step = step;
+    }
 }

+ 1 - 1
PHM-admin/phm-manage/src/main/java/com/phm/manage/service/impl/OrderInfoServiceImpl.java

@@ -54,7 +54,7 @@ public class OrderInfoServiceImpl implements IOrderInfoService {
      */
     @Override
     public int insertOrderInfo(OrderInfo orderInfo) {
-        orderInfo.initCreatInfo();
+        // orderInfo.initCreatInfo();
         orderInfo.setId(snowFlakeIdGenerator.nextId());
         return orderInfoMapper.insertOrderInfo(orderInfo);
     }

+ 37 - 0
PHM-admin/phm-manage/src/main/java/com/phm/manage/util/XMLParserWithJAXB.java

@@ -0,0 +1,37 @@
+package com.phm.manage.util;
+
+import com.phm.manage.domain.common.OrderXmlVO;
+import lombok.extern.slf4j.Slf4j;
+
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.JAXBException;
+import javax.xml.bind.Unmarshaller;
+import java.io.StringReader;
+
+/**
+ * @Description XMLParserWithJAXB
+ * @Author WGK
+ * @Date 2023/9/22 15:13
+ */
+@Slf4j
+public class XMLParserWithJAXB {
+    public static OrderXmlVO xmlToObject(String xmlString) {
+        OrderXmlVO xmlVO = null;
+        log.error(xmlString);
+        // 创建JAXB上下文
+        try {
+            JAXBContext context = JAXBContext.newInstance(OrderXmlVO.class);
+            // 创建Unmarshaller
+            Unmarshaller unmarshaller = context.createUnmarshaller();
+            // 解析XML字符串并将其转换为Java对象
+            xmlVO = (OrderXmlVO) unmarshaller.unmarshal(new StringReader(xmlString));
+
+            // 现在您可以使用yourObject对象
+            System.out.println("Type: " + xmlVO.getOrderType());
+            System.out.println("Name: " + xmlVO.getOrderName());
+        } catch (JAXBException exception) {
+            log.error(exception.getMessage());
+        }
+        return xmlVO;
+    }
+}

+ 0 - 6
PHM-admin/phm-netty/pom.xml

@@ -22,12 +22,6 @@
             <groupId>io.netty</groupId>
             <artifactId>netty-all</artifactId>
         </dependency>
-
-        <!-- 通用工具-->
-        <dependency>
-            <groupId>com.phm</groupId>
-            <artifactId>phm-common</artifactId>
-        </dependency>
         <dependency>
             <groupId>com.phm</groupId>
             <artifactId>phm-manage</artifactId>

+ 23 - 7
PHM-admin/phm-netty/src/main/java/com/phm/netty/codec/hexbyte/HexByteArrayDecoder.java

@@ -15,13 +15,29 @@ import java.util.List;
 public class HexByteArrayDecoder extends ByteToMessageDecoder {
     @Override
     protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
-        int readableBytes = in.readableBytes();
-        if (readableBytes < 2) {
-            return; // 不足2字节无法解析
+        // 检查是否有足够的字节可读
+        if (in.readableBytes() < 2) {
+            return;
         }
-        byte[] bytes = new byte[readableBytes];
-        in.readBytes(bytes);
-        ByteBufUtil.hexDump(in);
-        out.add(bytes);
+
+        // 读取前4个字节以获取消息长度
+        int messageLength = in.readInt();
+
+        // 检查是否有足够的字节可读以获取完整消息
+        if (in.readableBytes() < messageLength) {
+            return;
+        }
+
+        // 读取消息内容
+        ByteBuf messageBytes = in.readBytes(messageLength);
+
+        // 将消息内容转换为字节数组
+        byte[] messageArray = new byte[messageBytes.readableBytes()];
+        messageBytes.readBytes(messageArray);
+
+        // 在这里,您可以将字节数组转换为您需要的数据类型,如字符串、整数等,具体取决于您的数据格式。
+
+        // 将解码后的消息添加到输出列表,以便后续处理
+        out.add(messageArray);
     }
 }

+ 1 - 1
PHM-admin/phm-netty/src/main/java/com/phm/netty/config/NettyConfig.java

@@ -56,6 +56,6 @@ public class NettyConfig {
                 // 指定连接超时时间
                 .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, nettyProperties.getTimeout())
                 // 指定worker处理器
-                .childHandler(new NettyServerInitialize(nettyProperties));
+                .childHandler(new NettyServerInitialize());
     }
 }

+ 45 - 27
PHM-admin/phm-netty/src/main/java/com/phm/netty/domain/Message.java

@@ -1,15 +1,16 @@
 package com.phm.netty.domain;
 
 import cn.hutool.core.date.DateUtil;
+import cn.hutool.core.util.ObjectUtil;
 import com.alibaba.fastjson2.JSONObject;
+import com.phm.netty.utils.BitUtils;
 import com.phm.netty.utils.ByteUtils;
 import io.netty.util.CharsetUtil;
 import lombok.Data;
 import lombok.experimental.Accessors;
-import org.apache.commons.lang3.StringUtils;
 
+import javax.xml.bind.annotation.XmlRootElement;
 import java.io.Serializable;
-import java.util.Arrays;
 
 /**
  * @Description Message
@@ -42,12 +43,12 @@ public class Message implements Serializable {
     /**
      * 数据源
      */
-    private String source = StringUtils.rightPad("GPHM", 8);
+    private String source = "GPHM";
 
     /**
      * 目标
      */
-    private String target = StringUtils.rightPad("SPHM", 8);
+    private String target = "SPHM";
 
     /**
      * 目标
@@ -57,14 +58,25 @@ public class Message implements Serializable {
     public Message() {
     }
 
+    /**
+     * 字节数组解析为 Message 对象
+     *
+     * @param msg Message 对象
+     * @param buf 字节数组
+     * @param len 要解析的长度
+     */
     public static void bytesToMsg(Message msg, byte[] buf, int len) {
         int index = 0;
         msg.len = len;
-        msg.type = ByteUtils.toShort(buf, index);
+        msg.type = BitUtils.toShort(buf, index);
         index += 2;
-        msg.timestamp = ByteUtils.toInt(buf, index);
+        msg.source = BitUtils.toString(buf, index);
+        index += 8;
+        msg.target = BitUtils.toString(buf, index);
+        index += 8;
+        msg.timestamp = BitUtils.toInt(buf, index);
         index += 4;
-        msg.reserver = ByteUtils.toInt(buf, index);
+        msg.reserver = BitUtils.toInt(buf, index);
         index += 4;
         byte[] bytes = new byte[len - index];
         System.arraycopy(buf, index, bytes, 0, len - index);
@@ -72,37 +84,43 @@ public class Message implements Serializable {
     }
 
     public static void main(String[] args) {
+    }
+
+    public static byte[] testMsg() {
         Message message = new Message();
-        message.setLen(123).setTarget("GPHM").setSource("SPHM").setData("HHHHHHGGGFFFJHGSJDGHJSGDH");
-        byte[] byteArray = Message.msgToBytes(message,200);
-        System.out.println(Arrays.toString(byteArray));
+        message.setType((short) 1).setTarget("GPHM").setSource("SPHM").setData("<?xml version=\"1.0\" encoding=\"UTF-8\"?><root><orderName>故障预测</orderName><orderType>ERTYU</orderType></root>");
+        return Message.msgToBytes(message);
     }
 
-    public static byte[] msgToBytes(Message msg, int len) {
-        byte[] bytes = new byte[len + 4];
-        byte[] msgLenBytes = new byte[4];
-        msgLenBytes = ByteUtils.getBytes(msg.len, 4);
+    public static byte[] msgToBytes(Message msg) {
+        if (ObjectUtil.isEmpty(msg)) {
+            return new byte[0];
+        }
+        int dataLen = msg.data.getBytes().length;
+        msg.setLen(dataLen + 26);
+        byte[] bytes = new byte[msg.len + 4];
+        byte[] msgLenBytes = BitUtils.getBytes(msg.len);
         System.arraycopy(msgLenBytes, 0, bytes, 0, 4);
-        byte[] msgTypeBytes = new byte[2];
-        msgTypeBytes = ByteUtils.getBytes(msg.type, 2);
+        byte[] msgTypeBytes = BitUtils.getBytes(msg.type);
         System.arraycopy(msgTypeBytes, 0, bytes, 4, 2);
-        byte[] msgTimeStampBytes = new byte[4];
-        msgTimeStampBytes = ByteUtils.getBytes(msg.timestamp, 4);
-        System.arraycopy(msgTimeStampBytes, 0, bytes, 6, 4);
-        byte[] msgReserverBytes = new byte[4];
-        msgReserverBytes = ByteUtils.getBytes(msg.reserver, 4);
-        System.arraycopy(msgReserverBytes, 0, bytes, 10, 4);
-        byte[] msgDataBytes = new byte[len];
-        msgDataBytes = msg.getData().getBytes();
-        System.arraycopy(msgDataBytes, 0, bytes, 14, msgDataBytes.length);
+        byte[] msgSourceBytes = BitUtils.getBytes(msg.source, 8);
+        System.arraycopy(msgSourceBytes, 0, bytes, 6, 8);
+        byte[] msgTargetBytes = BitUtils.getBytes(msg.target, 8);
+        System.arraycopy(msgTargetBytes, 0, bytes, 14, 8);
+        byte[] msgTimeStampBytes = BitUtils.getBytes(msg.timestamp);
+        System.arraycopy(msgTimeStampBytes, 0, bytes, 22, 4);
+        byte[] msgReserverBytes = BitUtils.getBytes(msg.reserver);
+        System.arraycopy(msgReserverBytes, 0, bytes, 26, 4);
+        byte[] msgDataBytes = msg.getData().getBytes();
+        System.arraycopy(msgDataBytes, 0, bytes, 30, msgDataBytes.length);
         return bytes;
     }
 
     public Message(Object object) {
         String str = object.toString();
         JSONObject jsonObject = JSONObject.parseObject(str);
-        type = Short.valueOf(jsonObject.getString("type"));
-        data = jsonObject.getString("content");
+        type = Short.parseShort(jsonObject.getString("type"));
+        data = jsonObject.getString("data");
         len = str.length();
     }
 

+ 17 - 16
PHM-admin/phm-netty/src/main/java/com/phm/netty/enums/MessageEnum.java

@@ -16,34 +16,35 @@ import java.util.stream.Collectors;
 @Getter
 public enum MessageEnum {
 
-    GET_DATA_BY_ONBOARD(1, "机载数据获取指令"),
-    GET_DATA_BY_CHAIN(2, "数据链与数据仿真数据获取指令"),
-    FALSE_ALARM(3, "机载故障虚警抑制指令"),
-    ISOLATE(4, "机载故障深度隔离指令"),
-    GROUND_FAULT(5, "地面故障诊断指令"),
-    FAILURE_PREDICTION(6, "故障预测指令"),
-    FAILURE_PREDICTION1(7, "获取模型信息"),
-    FAILURE_PREDICTION2(8, "获取架次信息"),
-    ERROR(99, "异常信息"),
-    HEARTBEAT(100, "心跳机制"),
-    NTP(101, "校时机制");
+    GET_DATA_BY_ONBOARD((short) 1, "机载数据获取指令"),
+    GET_DATA_BY_CHAIN((short) 2, "数据链与数据仿真数据获取指令"),
+    FALSE_ALARM((short) 3, "机载故障虚警抑制指令"),
+    ISOLATE((short) 4, "机载故障深度隔离指令"),
+    GROUND_FAULT((short) 5, "地面故障诊断指令"),
+    FAILURE_PREDICTION((short) 6, "故障预测指令"),
+    // GET_MODEL((short) 7, "获取模型信息"),
+    GET_SORTIE((short) 8, "获取架次信息"),
+    ERROR((short) 99, "异常信息"),
+    HEARTBEAT((short) 100, "心跳机制"),
+    NTP((short) 101, "校时机制"),
+    SUCCESS((short) 200, "成功");
 
-    public final Integer type;
+    public final short type;
     public final String content;
 
-    MessageEnum(Integer type, String content) {
+    MessageEnum(short type, String content) {
         this.type = type;
         this.content = content;
     }
 
     // case中判断使用
     public static MessageEnum getStructureEnum(Message msg) {
-        Integer type = Integer.valueOf(Optional.ofNullable(msg)
+        short type = Optional.ofNullable(msg)
                 .map(Message::getType)
-                .orElse((short) 0));
+                .orElse((short) 0);
         if (type != 0) {
             List<MessageEnum> objectEnums = Arrays.stream(MessageEnum.values())
-                    .filter((item) -> item.getType().equals(type))
+                    .filter((item) -> item.getType() == type)
                     .distinct()
                     .collect(Collectors.toList());
             if (!objectEnums.isEmpty()) {

+ 0 - 7
PHM-admin/phm-netty/src/main/java/com/phm/netty/server/NettyServerInitialize.java

@@ -22,13 +22,6 @@ import org.springframework.stereotype.Component;
 @Component
 public class NettyServerInitialize extends ChannelInitializer<SocketChannel> {
 
-    final
-    NettyProperties nettyProperties;
-
-    public NettyServerInitialize(NettyProperties nettyProperties) {
-        this.nettyProperties = nettyProperties;
-    }
-
     @Override
     protected void initChannel(SocketChannel socketChannel) throws Exception {
         ChannelPipeline pipeline = socketChannel.pipeline();

+ 32 - 17
PHM-admin/phm-netty/src/main/java/com/phm/netty/server/handler/ByteArrayMessageHandler.java

@@ -2,8 +2,12 @@ package com.phm.netty.server.handler;
 
 import cn.hutool.core.collection.CollectionUtil;
 import cn.hutool.core.util.ObjectUtil;
-import com.phm.netty.service.IProcessService;
+import com.phm.netty.enums.MessageEnum;
 import com.phm.netty.domain.Message;
+import com.phm.netty.service.IProcessService;
+import com.phm.netty.service.impl.ProcessService;
+import com.phm.netty.utils.BitUtils;
+import com.phm.netty.utils.ByteUtils;
 import com.phm.netty.utils.ChannelMap;
 import io.netty.channel.Channel;
 import io.netty.channel.ChannelHandler;
@@ -14,6 +18,7 @@ import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Component;
 
+import javax.annotation.PostConstruct;
 import java.nio.ByteBuffer;
 
 /**
@@ -28,6 +33,13 @@ public class ByteArrayMessageHandler extends SimpleChannelInboundHandler<Object>
     @Autowired
     IProcessService processService;
 
+    private static ByteArrayMessageHandler byteArrayMessageHandler;
+
+
+    @PostConstruct
+    public void init() {
+        byteArrayMessageHandler = this;
+    }
     /**
      * 设备接入连接时处理
      *
@@ -37,27 +49,28 @@ public class ByteArrayMessageHandler extends SimpleChannelInboundHandler<Object>
     public void handlerAdded(ChannelHandlerContext ctx) {
         log.info("有新的连接:[{}]", ctx.channel().id().asLongText());
         Message msg = new Message();
-        msg.setData("和服务端连接成功");
-        msg.setTarget("Client");
-        msg.setSource("Serve");
-        ctx.channel().writeAndFlush(msg);
+        msg.setData(MessageEnum.SUCCESS.getContent()).setType(MessageEnum.SUCCESS.getType());
+        msg.setTarget("Client").setSource("Serve");
+        log.info("handlerAdded->Message Info : {}", msg);
+        ctx.channel().writeAndFlush(Message.msgToBytes(msg));
     }
 
     @Override
     protected void channelRead0(ChannelHandlerContext ctx, Object object) throws Exception {
         Message errorMsg = new Message();
-        errorMsg.setLen(35).setType((short) 99).setData("error");
-        byte[] binaryData = (byte[]) object;
-        binaryData = Message.msgToBytes(errorMsg, 35);
+        errorMsg.setType(MessageEnum.ERROR.getType());
+        // byte[] binaryData = (byte[]) object;
+        byte[] binaryData = Message.testMsg();
         // 处理接收到的二进制消息
         int len = 0;
         if (binaryData.length >= 4) {
-            // 使用 ByteBuffer 读取前4个字节并转换为整数
-            ByteBuffer buffer = ByteBuffer.wrap(binaryData, 0, 4);
-            len = buffer.getInt();
+            // 读取的字节长度
+            len = BitUtils.toInt(binaryData, 0);
         }
-        if (len == 0) {
-            ctx.writeAndFlush(Message.msgToBytes(errorMsg, errorMsg.getLen()));
+        if (len <= 0) {
+            log.error("解析len属性,条件不满足:{}", len);
+            errorMsg.setData("len 格式不对,非正整数");
+            ctx.writeAndFlush(Message.msgToBytes(errorMsg));
             return;
         }
         // 创建一个新的字节数组来存储截取的部分
@@ -66,14 +79,16 @@ public class ByteArrayMessageHandler extends SimpleChannelInboundHandler<Object>
         System.arraycopy(binaryData, 4, subArray, 0, len);
         Message msg = new Message();
         Message.bytesToMsg(msg, subArray, len);
-        Message lastMsg = processService.orderHandle(msg);
-        log.info("输出传输的内容对象:{}", lastMsg);
+        Message lastMsg = byteArrayMessageHandler.processService.orderHandle(msg);
         if (ObjectUtil.isEmpty(lastMsg)) {
-            ctx.writeAndFlush(Message.msgToBytes(errorMsg, errorMsg.getLen()));
+            log.info("Message:{}", lastMsg);
+            errorMsg.setData("Message数据为空");
+            ctx.writeAndFlush(Message.msgToBytes(errorMsg));
             return;
         }
+        log.info("输出传输的内容对象:{}", lastMsg);
         // 转byte[] 返回消息
-        ctx.writeAndFlush(Message.msgToBytes(lastMsg, lastMsg.getLen()));
+        ctx.writeAndFlush(Message.msgToBytes(lastMsg));
     }
 
     /**

+ 5 - 1
PHM-admin/phm-netty/src/main/java/com/phm/netty/server/handler/HeartbeatHandler.java

@@ -1,5 +1,7 @@
 package com.phm.netty.server.handler;
 
+import com.phm.netty.domain.Message;
+import com.phm.netty.enums.MessageEnum;
 import io.netty.buffer.ByteBuf;
 import io.netty.buffer.Unpooled;
 import io.netty.channel.ChannelFutureListener;
@@ -24,7 +26,9 @@ public class HeartbeatHandler extends ChannelInboundHandlerAdapter {
             // 如果触发了空闲事件,发送心跳消息
             IdleStateEvent e = (IdleStateEvent) evt;
             if (e.state() == IdleState.WRITER_IDLE) {
-                ctx.writeAndFlush(HEARTBEAT_MESSAGE.duplicate()).addListener(ChannelFutureListener.CLOSE_ON_FAILURE);
+                Message message = new Message();
+                message.setType(MessageEnum.HEARTBEAT.getType()).setData(MessageEnum.HEARTBEAT.getContent());
+                ctx.writeAndFlush(Unpooled.wrappedBuffer(Message.msgToBytes(message))).addListener(ChannelFutureListener.CLOSE_ON_FAILURE);
             }
         } else {
             super.userEventTriggered(ctx, evt);

+ 0 - 1
PHM-admin/phm-netty/src/main/java/com/phm/netty/server/handler/ServerListenerHandler.java

@@ -49,7 +49,6 @@ public class ServerListenerHandler extends SimpleChannelInboundHandler<Message>
         String content = msg.getData();
 //        msg.setId(ctx.channel().id().asLongText());
         // 对不同消息类型进行处理
-        MessageEnum type = MessageEnum.getStructureEnum(msg);
         this.channelWrite(ctx.channel(), msg);
 //        switch (Objects.requireNonNull(type)) {
 //            case GET_DATA_BY_ONBOARD:

+ 59 - 1
PHM-admin/phm-netty/src/main/java/com/phm/netty/service/impl/ProcessService.java

@@ -1,18 +1,76 @@
 package com.phm.netty.service.impl;
 
+import com.alibaba.fastjson2.JSON;
+import com.phm.common.utils.bean.BeanUtils;
+import com.phm.manage.domain.OrderInfo;
+import com.phm.manage.domain.common.OrderXmlVO;
+import com.phm.manage.enums.OrderStatus;
+import com.phm.manage.service.IOrderInfoService;
+import com.phm.manage.service.ISortieService;
+import com.phm.manage.util.XMLParserWithJAXB;
+import com.phm.netty.enums.MessageEnum;
 import com.phm.netty.service.IProcessService;
 import com.phm.netty.domain.Message;
+import com.phm.system.service.ISysDictDataService;
+import com.phm.system.service.ISysDictTypeService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Lazy;
 import org.springframework.stereotype.Service;
 
+import java.util.Objects;
+
+import static com.phm.netty.enums.MessageEnum.GET_DATA_BY_ONBOARD;
+
 /**
  * @Description ProcessService
  * @Author WGK
  * @Date 2023/9/22 9:54
  */
+
 @Service
 public class ProcessService implements IProcessService {
+
+    @Autowired
+    private IOrderInfoService orderInfoService;
+
+    @Autowired
+    private ISysDictTypeService dictTypeService;
+
+    @Autowired
+    private ISortieService sortieService;
+
     @Override
     public Message orderHandle(Message message) {
-        return null;
+        MessageEnum type = MessageEnum.getStructureEnum(message);
+        OrderXmlVO orderXmlVO = XMLParserWithJAXB.xmlToObject(message.getData());
+        OrderInfo orderInfo = new OrderInfo();
+        BeanUtils.copyBeanProp(orderInfo, orderXmlVO);
+        orderInfo.setContent(JSON.toJSONString(message.getData()));
+        // set待执行状态
+        orderInfo.setStatus(OrderStatus.S_0.getCode());
+        orderInfoService.insertOrderInfo(orderInfo);
+        Message msg = new Message();
+        msg.setType(MessageEnum.SUCCESS.getType()).setData(MessageEnum.SUCCESS.getContent());
+        switch (Objects.requireNonNull(type)) {
+            case GET_DATA_BY_ONBOARD:
+                // 机载数据获取指令
+            case GET_DATA_BY_CHAIN:
+                // 数据链与数据仿真数据获取指令
+            case FALSE_ALARM:
+                // 机载故障虚警抑制指令
+            case ISOLATE:
+                // 机载故障深度隔离指令
+            case GROUND_FAULT:
+                // 地面故障诊断指令
+            case FAILURE_PREDICTION:
+                // 故障预测指令
+            case GET_SORTIE:
+                // 获取架次信息
+            case NTP:
+                // 校时
+            default:
+                // 默认
+                return msg;
+        }
     }
 }

+ 463 - 0
PHM-admin/phm-netty/src/main/java/com/phm/netty/utils/BitUtils.java

@@ -0,0 +1,463 @@
+package com.phm.netty.utils;
+
+import io.netty.util.CharsetUtil;
+
+import java.nio.ByteOrder;
+import java.nio.charset.Charset;
+import java.util.Arrays;
+
+/**
+ * @Description BitUtils
+ * @Author WGK
+ * @Date 2023/9/22 16:07
+ */
+public class BitUtils {
+
+
+    /**
+     * 以字节数组的形式返回指定的布尔值
+     *
+     * @param data 一个布尔值
+     * @return 长度为 1 的字节数组
+     */
+
+    public static byte[] getBytes(boolean data) {
+        byte[] bytes = new byte[1];
+        bytes[0] = (byte) (data ? 1 : 0);
+        return bytes;
+    }
+
+    /**
+     * 以字节数组的形式返回指定的 16 位有符号整数值
+     *
+     * @param data 要转换的数字
+     * @return 长度为 2 的字节数组
+     */
+
+    public static byte[] getBytes(short data) {
+        byte[] bytes = new byte[2];
+        if (isLittleEndian()) {
+            bytes[0] = (byte) (data & 0xff);
+            bytes[1] = (byte) ((data & 0xff00) >> 8);
+        } else {
+            bytes[1] = (byte) (data & 0xff);
+            bytes[0] = (byte) ((data & 0xff00) >> 8);
+        }
+        return bytes;
+    }
+
+    /**
+     * 以字节数组的形式返回指定的 Unicode 字符值
+     *
+     * @param data 要转换的字符
+     * @return 长度为 2 的字节数组
+     */
+
+    public static byte[] getBytes(char data) {
+        byte[] bytes = new byte[2];
+        if (isLittleEndian()) {
+            bytes[0] = (byte) (data);
+            bytes[1] = (byte) (data >> 8);
+        } else {
+            bytes[1] = (byte) (data);
+            bytes[0] = (byte) (data >> 8);
+        }
+        return bytes;
+    }
+
+    /**
+     * 以字节数组的形式返回指定的 32 位有符号整数值
+     *
+     * @param data 要转换的数字
+     * @return 长度为 4 的字节数组
+     */
+
+    public static byte[] getBytes(int data) {
+        byte[] bytes = new byte[4];
+        if (isLittleEndian()) {
+            bytes[0] = (byte) (data & 0xff);
+            bytes[1] = (byte) ((data & 0xff00) >> 8);
+            bytes[2] = (byte) ((data & 0xff0000) >> 16);
+            bytes[3] = (byte) ((data & 0xff000000) >> 24);
+        } else {
+            bytes[3] = (byte) (data & 0xff);
+            bytes[2] = (byte) ((data & 0xff00) >> 8);
+            bytes[1] = (byte) ((data & 0xff0000) >> 16);
+            bytes[0] = (byte) ((data & 0xff000000) >> 24);
+        }
+        return bytes;
+    }
+
+    /**
+     * 以字节数组的形式返回指定的 64 位有符号整数值
+     *
+     * @param data 要转换的数字
+     * @return 长度为 8 的字节数组
+     */
+
+    public static byte[] getBytes(long data) {
+        byte[] bytes = new byte[8];
+        if (isLittleEndian()) {
+            bytes[0] = (byte) (data & 0xff);
+            bytes[1] = (byte) ((data >> 8) & 0xff);
+            bytes[2] = (byte) ((data >> 16) & 0xff);
+            bytes[3] = (byte) ((data >> 24) & 0xff);
+            bytes[4] = (byte) ((data >> 32) & 0xff);
+            bytes[5] = (byte) ((data >> 40) & 0xff);
+            bytes[6] = (byte) ((data >> 48) & 0xff);
+            bytes[7] = (byte) ((data >> 56) & 0xff);
+        } else {
+            bytes[7] = (byte) (data & 0xff);
+            bytes[6] = (byte) ((data >> 8) & 0xff);
+            bytes[5] = (byte) ((data >> 16) & 0xff);
+            bytes[4] = (byte) ((data >> 24) & 0xff);
+            bytes[3] = (byte) ((data >> 32) & 0xff);
+            bytes[2] = (byte) ((data >> 40) & 0xff);
+            bytes[1] = (byte) ((data >> 48) & 0xff);
+            bytes[0] = (byte) ((data >> 56) & 0xff);
+        }
+        return bytes;
+    }
+
+    /**
+     * 以字节数组的形式返回指定的单精度浮点值
+     *
+     * @param data 要转换的数字
+     * @return 长度为 4 的字节数组
+     */
+
+    public static byte[] getBytes(float data) {
+        return getBytes(Float.floatToIntBits(data));
+    }
+
+    /**
+     * 以字节数组的形式返回指定的双精度浮点值
+     *
+     * @param data 要转换的数字
+     * @return 长度为 8 的字节数组
+     */
+
+    public static byte[] getBytes(double data) {
+        return getBytes(Double.doubleToLongBits(data));
+    }
+
+    /**
+     * 将指定字符串中的所有字符编码为一个字节序列
+     *
+     * @param data 包含要编码的字符的字符串
+     * @return 一个字节数组,包含对指定的字符集进行编码的结果
+     */
+
+    public static byte[] getBytes(String data) {
+        return data.getBytes(CharsetUtil.UTF_8);
+    }
+
+    /**
+     * 得到固定位数的数组
+     *
+     * @param data 字符
+     * @param len 确定长度
+     * @return 结果
+     */
+    public static byte[] getBytes(String data, int len) {
+        byte[] sDate = data.getBytes();
+        byte[] resultArray = new byte[len];
+        Arrays.fill(resultArray, (byte) 0); // 填充 0
+        System.arraycopy(sDate, 0, resultArray, 0, sDate.length);
+        return resultArray;
+    }
+
+    /**
+     * 将指定字符串中的所有字符编码为一个字节序列
+     *
+     * @param data        包含要编码的字符的字符串
+     * @param charsetName 字符集编码
+     * @return 一个字节数组,包含对指定的字符集进行编码的结果
+     */
+
+    public static byte[] getBytes(String data, String charsetName) {
+        return data.getBytes(Charset.forName(charsetName));
+    }
+
+    /**
+     * 返回由字节数组转换来的布尔值
+     *
+     * @param bytes 字节数组
+     * @return 布尔值
+     */
+
+    public static boolean toBoolean(byte[] bytes) {
+        return bytes[0] == 0 ? false : true;
+    }
+
+    /**
+     * 返回由字节数组中的指定的一个字节转换来的布尔值
+     *
+     * @param bytes      字节数组
+     * @param startIndex 起始下标
+     * @return 布尔值
+     */
+
+    public static boolean toBoolean(byte[] bytes, int startIndex) {
+        return toBoolean(copyFrom(bytes, startIndex, 1));
+    }
+
+    /**
+     * 返回由字节数组转换来的 16 位有符号整数
+     *
+     * @param bytes 字节数组
+     * @return 由两个字节构成的 16 位有符号整数
+     */
+
+    public static short toShort(byte[] bytes) {
+        if (isLittleEndian()) {
+            return (short) ((0xff & bytes[0]) | (0xff00 & (bytes[1] << 8)));
+        } else {
+            return (short) ((0xff & bytes[1]) | (0xff00 & (bytes[0] << 8)));
+        }
+    }
+
+    /**
+     * 返回由字节数组中的指定的两个字节转换来的 16 位有符号整数
+     *
+     * @param bytes      字节数组
+     * @param startIndex 起始下标
+     * @return 由两个字节构成的 16 位有符号整数
+     */
+
+    public static short toShort(byte[] bytes, int startIndex) {
+        return toShort(copyFrom(bytes, startIndex, 2));
+    }
+
+    /**
+     * 返回由字节数组转换来的 Unicode 字符
+     *
+     * @param bytes 字节数组
+     * @return 由两个字节构成的字符
+     */
+
+    public static char toChar(byte[] bytes) {
+        if (isLittleEndian()) {
+            return (char) ((0xff & bytes[0]) | (0xff00 & (bytes[1] << 8)));
+        } else {
+            return (char) ((0xff & bytes[1]) | (0xff00 & (bytes[0] << 8)));
+        }
+    }
+
+    /**
+     * 返回由字节数组中的指定的两个字节转换来的 Unicode 字符
+     *
+     * @param bytes      字节数组
+     * @param startIndex 起始下标
+     * @return 由两个字节构成的字符
+     */
+
+    public static char toChar(byte[] bytes, int startIndex) {
+        return toChar(copyFrom(bytes, startIndex, 2));
+    }
+
+    /**
+     * 返回由字节数组转换来的 32 位有符号整数
+     *
+     * @param bytes 字节数组
+     * @return 由四个字节构成的 32 位有符号整数
+     */
+
+    public static int toInt(byte[] bytes) {
+        if (isLittleEndian()) {
+            return (0xff & bytes[0])
+                    | (0xff00 & (bytes[1] << 8))
+                    | (0xff0000 & (bytes[2] << 16))
+                    | (0xff000000 & (bytes[3] << 24));
+        } else {
+            return (0xff & bytes[3])
+                    | (0xff00 & (bytes[2] << 8))
+                    | (0xff0000 & (bytes[1] << 16))
+                    | (0xff000000 & (bytes[0] << 24));
+        }
+    }
+
+    /**
+     * 返回由字节数组中的指定的四个字节转换来的 32 位有符号整数
+     *
+     * @param bytes      字节数组
+     * @param startIndex 起始下标
+     * @return 由四个字节构成的 32 位有符号整数
+     */
+
+    public static int toInt(byte[] bytes, int startIndex) {
+        return toInt(copyFrom(bytes, startIndex, 4));
+    }
+
+    /**
+     * 返回由字节数组转换来的 64 位有符号整数
+     *
+     * @param bytes 字节数组
+     * @return 由八个字节构成的 64 位有符号整数
+     */
+
+    public static long toLong(byte[] bytes) {
+        if (isLittleEndian()) {
+            return (0xffL & (long) bytes[0])
+                    | (0xff00L & ((long) bytes[1] << 8))
+                    | (0xff0000L & ((long) bytes[2] << 16))
+                    | (0xff000000L & ((long) bytes[3] << 24))
+                    | (0xff00000000L & ((long) bytes[4] << 32))
+                    | (0xff0000000000L & ((long) bytes[5] << 40))
+                    | (0xff000000000000L & ((long) bytes[6] << 48))
+                    | (0xff00000000000000L & ((long) bytes[7] << 56));
+        } else {
+            return (0xffL & (long) bytes[7])
+                    | (0xff00L & ((long) bytes[6] << 8))
+                    | (0xff0000L & ((long) bytes[5] << 16))
+                    | (0xff000000L & ((long) bytes[4] << 24))
+                    | (0xff00000000L & ((long) bytes[3] << 32))
+                    | (0xff0000000000L & ((long) bytes[2] << 40))
+                    | (0xff000000000000L & ((long) bytes[1] << 48))
+                    | (0xff00000000000000L & ((long) bytes[0] << 56));
+        }
+    }
+
+    /**
+     * 返回由字节数组中的指定的八个字节转换来的 64 位有符号整数
+     *
+     * @param bytes      字节数组
+     * @param startIndex 起始下标
+     * @return 由八个字节构成的 64 位有符号整数
+     */
+
+    public static long toLong(byte[] bytes, int startIndex) {
+        return toLong(copyFrom(bytes, startIndex, 8));
+    }
+
+    /**
+     * 返回由字节数组转换来的单精度浮点数
+     *
+     * @param bytes 字节数组
+     * @return 由四个字节构成的单精度浮点数
+     */
+
+    public static float toFloat(byte[] bytes) {
+        return Float.intBitsToFloat(toInt(bytes));
+    }
+
+    /**
+     * 返回由字节数组中的指定的四个字节转换来的单精度浮点数
+     *
+     * @param bytes      字节数组
+     * @param startIndex 起始下标
+     * @return 由四个字节构成的单精度浮点数
+     */
+
+    public static float toFloat(byte[] bytes, int startIndex) {
+        return Float.intBitsToFloat(toInt(copyFrom(bytes, startIndex, 4)));
+    }
+
+    /**
+     * 返回由字节数组转换来的双精度浮点数
+     *
+     * @param bytes 字节数组
+     * @return 由八个字节构成的双精度浮点数
+     */
+
+    public static double toDouble(byte[] bytes) {
+        return Double.longBitsToDouble(toLong(bytes));
+    }
+
+    /**
+     * 返回由字节数组中的指定的八个字节转换来的双精度浮点数
+     *
+     * @param bytes      字节数组
+     * @param startIndex 起始下标
+     * @return 由八个字节构成的双精度浮点数
+     */
+
+    public static double toDouble(byte[] bytes, int startIndex) {
+        return Double.longBitsToDouble(toLong(copyFrom(bytes, startIndex, 8)));
+    }
+
+    /**
+     * 返回由字节数组转换来的字符串
+     *
+     * @param bytes 字节数组
+     * @return 字符串
+     */
+
+    public static String toString(byte[] bytes) {
+        return new String(bytes, CharsetUtil.UTF_8);
+    }
+
+    /**
+     * 返回由字节数组转换来的字符串
+     *
+     * @param bytes       字节数组
+     * @param charsetName 字符集编码
+     * @return 字符串
+     */
+
+    public static String toString(byte[] bytes, String charsetName) {
+        return new String(bytes, Charset.forName(charsetName));
+    }
+
+    /**
+     * 解析固定数组的值
+     *
+     * @param bytes 源数据
+     * @param startIndex 开始索引
+     * @return 结果
+     */
+    public static String toString(byte[] bytes, int startIndex) {
+        return new String(copyFrom(bytes, startIndex, 2), CharsetUtil.UTF_8);
+    }
+
+    /**
+     * 以字符串表示形式返回字节数组的内容
+     *
+     * @param bytes 字节数组
+     * @return 字符串形式的 bytes
+     */
+
+    public static String toHexString(byte[] bytes) {
+        if (bytes == null)
+            return "null";
+        int iMax = bytes.length - 1;
+        if (iMax == -1)
+            return "[]";
+        StringBuilder b = new StringBuilder();
+        b.append('[');
+        for (int i = 0; ; i++) {
+            b.append(String.format("%02x", bytes[i] & 0xFF));
+            if (i == iMax)
+                return b.append(']').toString();
+            b.append(", ");
+        }
+    }
+
+    /**
+     * 数组拷贝。
+     *
+     * @param src 字节数组。
+     * @param off 起始下标。
+     * @param len 拷贝长度。
+     * @return 指定长度的字节数组。
+     */
+
+    private static byte[] copyFrom(byte[] src, int off, int len) {
+        // return Arrays.copyOfRange(src, off, off + len);
+        byte[] bits = new byte[len];
+        for (int i = off, j = 0; i < src.length && j < len; i++, j++) {
+            bits[j] = src[i];
+        }
+        return bits;
+    }
+
+    /**
+     * 判断 CPU Endian 是否为 Little
+     *
+     * @return 判断结果
+     */
+
+    private static boolean isLittleEndian() {
+        return ByteOrder.nativeOrder() == ByteOrder.LITTLE_ENDIAN;
+    }
+}