From d6d31aee87a56e8d4c4bcc19135bd348be2ba373 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=8F=E9=B1=BC=E5=B9=B2?= <1810377322@163.com> Date: Mon, 28 Oct 2024 16:39:46 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E6=B6=88=E6=81=AF=E5=9B=9E?= =?UTF-8?q?=E5=A4=8D\=E6=A0=A1=E9=AA=8C=E7=A0=81=E7=94=9F=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/hive/bee/entity/BeeHive.java | 5 +- .../dataprocessing/HandlerDateProcessing.java | 1 + .../server/handler/EchoServerHandler.java | 101 +++++++++++------- .../hive/communication/util/CheckCode.java | 49 ++++----- 4 files changed, 94 insertions(+), 62 deletions(-) diff --git a/src/main/java/com/hive/bee/entity/BeeHive.java b/src/main/java/com/hive/bee/entity/BeeHive.java index 4d66e44..3824f8e 100644 --- a/src/main/java/com/hive/bee/entity/BeeHive.java +++ b/src/main/java/com/hive/bee/entity/BeeHive.java @@ -94,5 +94,8 @@ public class BeeHive implements Serializable { * 数据上传时间 */ private LocalDateTime dateUploadTime; - + /** + * 数据上传时间原始数据 + */ + private String dateUploadTimeHex; } \ No newline at end of file diff --git a/src/main/java/com/hive/communication/netty/server/dataprocessing/HandlerDateProcessing.java b/src/main/java/com/hive/communication/netty/server/dataprocessing/HandlerDateProcessing.java index a24ccc1..deb7615 100644 --- a/src/main/java/com/hive/communication/netty/server/dataprocessing/HandlerDateProcessing.java +++ b/src/main/java/com/hive/communication/netty/server/dataprocessing/HandlerDateProcessing.java @@ -116,6 +116,7 @@ public class HandlerDateProcessing { // return null; // } beeHive.setDateUploadTime(LocalDateTime.ofInstant(Instant.ofEpochSecond(date), ZoneId.systemDefault())); + beeHive.setDateUploadTimeHex(getSubData(data, startIndex, endIndex)); break; case 2: //当前温度值2 diff --git a/src/main/java/com/hive/communication/netty/server/handler/EchoServerHandler.java b/src/main/java/com/hive/communication/netty/server/handler/EchoServerHandler.java index f22c866..5ec3f2d 100644 --- a/src/main/java/com/hive/communication/netty/server/handler/EchoServerHandler.java +++ b/src/main/java/com/hive/communication/netty/server/handler/EchoServerHandler.java @@ -12,6 +12,7 @@ import io.netty.handler.timeout.ReadTimeoutException; import io.netty.util.AttributeKey; import io.netty.util.CharsetUtil; import lombok.extern.slf4j.Slf4j; + import java.io.UnsupportedEncodingException; import java.net.InetSocketAddress; import java.net.SocketAddress; @@ -20,6 +21,7 @@ import java.util.HashMap; import java.util.Map; import java.util.concurrent.*; +import static com.hive.communication.util.CheckCode.*; import static com.hive.util.DateConvetUtil.getCurrentSeconds; @Slf4j @@ -43,33 +45,55 @@ public class EchoServerHandler extends ChannelInboundHandlerAdapter { * 当客户端主动链接服务端的链接后,这个通道就是活跃的了。也就是客户端与服务端建立了通信通道并且可以传输数据 */ - public static void sendActive(ChannelHandlerContext ctx, boolean flag, BeeHive beeHive, boolean notice) { + public static void sendActive(ChannelHandlerContext ctx, boolean flag, BeeHive beeHive, boolean notice) { if (flag) { - try { - // String paddedString = String.format("%4s", code).replace(' ', '0'); - String codes = "注册完回复"; - //获取十分钟后的时间秒数,需要转换为16进制 - getCurrentSeconds(); - log.info("当前时间: {}, 消息: {}", LocalDateTime.now(), codes); - // 先将十六进制字符串转换为字节数组 - byte[] messageBytes = HexConversion.hexStringToByteArray(codes); - // 将字节数组封装到ByteBuf中 - ByteBuf messageBuffer = Unpooled.wrappedBuffer(messageBytes); - // 通过ChannelHandlerContext发送ByteBuf - // 关联设备编号与Channel - // sendRequest(ctx.channel(),messageBuffer,devicePointsSensor.getId()); - retrySend(ctx, messageBuffer) - .whenComplete((result,error) -> { - log.info("发送状态: {},当前时间: {}, 消息: {},名称:{},蜂箱id:{}", result,LocalDateTime.now(), codes,beeHive.getBeeHiveName(),beeHive.getId()); + try { + String start="99"; + String end ="AA"; + StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.append(start); + stringBuilder.append("8561"); + stringBuilder.append(beeHive.getDateUploadTimeHex()); + stringBuilder.append("0b01"); + // String paddedString = String.format("%4s", code).replace(' ', '0'); + //获取十分钟后的时间秒数, + // 转换为16进制 + String hexSeconds = Long.toHexString(getCurrentSeconds()).toUpperCase(); + stringBuilder.append(hexSeconds); + stringBuilder.append("0000ff000000"); + + byte[] dataSum = hexStringToByteArray(stringBuilder.toString()); + // 计算校验码1 + byte checksum1 = calculateChecksum1(dataSum); + // 计算校验码2 + byte checksum2 = calculateChecksum2(dataSum); + String checksum1Hex = String.format("%02X", checksum1); + String checksum2Hex = String.format("%02X", checksum2); + stringBuilder.append(checksum1Hex); + stringBuilder.append(checksum2Hex); + stringBuilder.append(end); + + log.info("当前时间: {}, 消息: {}", LocalDateTime.now(), stringBuilder); + // 先将十六进制字符串转换为字节数组 + byte[] messageBytes = HexConversion.hexStringToByteArray(stringBuilder.toString()); + // 将字节数组封装到ByteBuf中 + ByteBuf messageBuffer = Unpooled.wrappedBuffer(messageBytes); + + // 通过ChannelHandlerContext发送ByteBuf + // 关联设备编号与Channel + // sendRequest(ctx.channel(),messageBuffer,devicePointsSensor.getId()); + retrySend(ctx, messageBuffer) + .whenComplete((result, error) -> { + log.info("发送状态: {},当前时间: {}, 消息: {},名称:{},蜂箱id:{}", result, LocalDateTime.now(), stringBuilder, beeHive.getBeeHiveName(), beeHive.getId()); /* if (result) { // 发送成功 } else { // 发送失败 }*/ - }); - } catch (Exception e) { - // 处理异常 - } + }); + } catch (Exception e) { + // 处理异常 + } } } @@ -92,6 +116,7 @@ public class EchoServerHandler extends ChannelInboundHandlerAdapter { } return future; } + /** * 功能:发送消息并监听成功与失败进行重试 */ @@ -99,31 +124,32 @@ public class EchoServerHandler extends ChannelInboundHandlerAdapter { messageBuffer.retain(); // 增加引用计数 ChannelFuture sendFuture = ctx.writeAndFlush(messageBuffer); sendFuture.addListener((ChannelFutureListener) sendFutureListener -> { - if (sendFutureListener.isSuccess()) { - messageBuffer.release(); // 释放在发送前增加的引用计数 - future.complete(true); // 发送成功,将结果设置为 true - } else { - if (remainingRetries > 0) { - ctx.executor().schedule(() -> { + if (sendFutureListener.isSuccess()) { + messageBuffer.release(); // 释放在发送前增加的引用计数 + future.complete(true); // 发送成功,将结果设置为 true + } else { + if (remainingRetries > 0) { + ctx.executor().schedule(() -> { // 发送失败,但还有剩余重试次数 if (messageBuffer.isReadable()) { // 如果messageBuffer仍然可读,重新使用它进行重试 - retrySendAsync(ctx,messageBuffer, remainingRetries - 1, future); + retrySendAsync(ctx, messageBuffer, remainingRetries - 1, future); } else { // messageBuffer不可读,需要重新创建或复制一个新的messageBuffer ByteBuf newMessageBuffer = messageBuffer.retainedDuplicate(); retrySendAsync(ctx, newMessageBuffer, remainingRetries - 1, future); - } - }, 2, TimeUnit.SECONDS); - } else { - messageBuffer.release(); // 释放在发送前增加的引用计数 - future.complete(false); // 达到最大重试次数,将结果设置为 false + } + }, 2, TimeUnit.SECONDS); + } else { + messageBuffer.release(); // 释放在发送前增加的引用计数 + future.complete(false); // 达到最大重试次数,将结果设置为 false - } } + } }); } + /** * 功能:或缺设备编号等存入pendingRequests等读取是进行匹配 */ @@ -142,6 +168,7 @@ public class EchoServerHandler extends ChannelInboundHandlerAdapter { return promise; } + /** * 功能:连接成功调用 */ @@ -179,7 +206,7 @@ public class EchoServerHandler extends ChannelInboundHandlerAdapter { return null; } } - /*****************************************处理收到的消息 *****************************************/ + /*****************************************处理收到的消息 *****************************************/ /** * 功能:读取发送过来的信息 @@ -200,7 +227,7 @@ public class EchoServerHandler extends ChannelInboundHandlerAdapter { // System.out.println("接收到的数据sb" + sb.toString()); // 检查消息是否是心跳请求 if (sb.toString().equalsIgnoreCase(HEARTBEAT_REQUEST)) { - handleHeartbeat(ctx,msg); + handleHeartbeat(ctx, msg); } else { // 如果不是心跳请求,调用ChannelInboundHandler的下一个处理器 ctx.fireChannelRead(msg); @@ -214,7 +241,7 @@ public class EchoServerHandler extends ChannelInboundHandlerAdapter { private void handleHeartbeat(ChannelHandlerContext ctx, Object msg) { isHeartbeatReceived = true; - ctx.fireChannelRead(msg); + ctx.fireChannelRead(msg); //ctx.fireChannelReadComplete(); // 如果需要,发送心跳响应 // ctx.writeAndFlush("FE"); diff --git a/src/main/java/com/hive/communication/util/CheckCode.java b/src/main/java/com/hive/communication/util/CheckCode.java index 7503b8f..e4078e0 100644 --- a/src/main/java/com/hive/communication/util/CheckCode.java +++ b/src/main/java/com/hive/communication/util/CheckCode.java @@ -1,35 +1,36 @@ package com.hive.communication.util; + + public class CheckCode { - // 计算字符串的校验码(异位校验) - public static int calculateParity(String input, boolean oddParity) { - int parity = 0; - for (char ch : input.toCharArray()) { - parity ^= ch; - } - // 根据需要调整奇偶校验位 - int parityBit = Integer.bitCount(parity) % 2; - if (oddParity) { - parityBit = parityBit == 0 ? 1 : 0; // 奇校验:如果0变成1,如果1变成0 + + // 计算校验码1(按位异或操作) + public static byte calculateChecksum1(byte[] data) { + byte checksum = 0x00; + for (byte b : data) { + checksum ^= b; } - return parityBit; + return checksum; } - // 计算16进制字符串的校验码 - public static int calculateChecksum(String hexString) { - int sum = 0; - // 每两个字符作为一个16进制数进行解析 - for (int i = 0; i < hexString.length(); i += 2) { - String hexPair = hexString.substring(i, i + 2); - int hexValue = Integer.parseInt(hexPair, 16); - sum += hexValue; + // 计算校验码2(加法操作) + public static byte calculateChecksum2(byte[] data) { + int sum = 0; + for (byte b : data) { + sum += b & 0xFF; // & 0xFF 保证每个 byte 被当作无符号处理 } - - // 保留最后8位 - int checksum = sum & 0xFF; // 0xFF表示8位全1的掩码 - - return checksum; + return (byte) (sum & 0xFF); // 取最后8位 } + // 将十六进制字符串转换为字节数组 + public static byte[] hexStringToByteArray(String s) { + int len = s.length(); + byte[] data = new byte[len / 2]; + for (int i = 0; i < len; i += 2) { + data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4) + + Character.digit(s.charAt(i+1), 16)); + } + return data; + } }