Commit 8449ccbb7d7d13b51a1665c8b49d3d46ca551a9b

Authored by haohao
1 parent 00bd4293

feat:【IoT 物联网】优化 TCP 二进制协议的消息编码和解码逻辑

yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/codec/tcp/IotTcpBinaryDeviceMessageCodec.java
... ... @@ -4,10 +4,9 @@ import cn.hutool.core.lang.Assert;
4 4 import cn.hutool.core.util.StrUtil;
5 5 import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
6 6 import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage;
  7 +import cn.iocoder.yudao.module.iot.core.util.IotDeviceMessageUtils;
7 8 import cn.iocoder.yudao.module.iot.gateway.codec.IotDeviceMessageCodec;
8 9 import io.vertx.core.buffer.Buffer;
9   -import lombok.AllArgsConstructor;
10   -import lombok.Data;
11 10 import lombok.extern.slf4j.Slf4j;
12 11 import org.springframework.stereotype.Component;
13 12  
... ... @@ -19,9 +18,9 @@ import java.nio.charset.StandardCharsets;
19 18 * 二进制协议格式(所有数值使用大端序):
20 19 *
21 20 * <pre>
22   - * +--------+--------+--------+--------+--------+--------+--------+--------+
23   - * | 魔术字 | 版本号 | 消息类型| 消息标志| 消息长度(4 字节) |
24   - * +--------+--------+--------+--------+--------+--------+--------+--------+
  21 + * +--------+--------+--------+---------------------------+--------+--------+
  22 + * | 魔术字 | 版本号 | 消息类型| 消息长度(4 字节) |
  23 + * +--------+--------+--------+---------------------------+--------+--------+
25 24 * | 消息 ID 长度(2 字节) | 消息 ID (变长字符串) |
26 25 * +--------+--------+--------+--------+--------+--------+--------+--------+
27 26 * | 方法名长度(2 字节) | 方法名(变长字符串) |
... ... @@ -44,8 +43,6 @@ public class IotTcpBinaryDeviceMessageCodec implements IotDeviceMessageCodec {
44 43  
45 44 public static final String TYPE = "TCP_BINARY";
46 45  
47   - // ==================== 协议常量 ====================
48   -
49 46 /**
50 47 * 协议魔术字,用于协议识别
51 48 */
... ... @@ -56,27 +53,20 @@ public class IotTcpBinaryDeviceMessageCodec implements IotDeviceMessageCodec {
56 53 */
57 54 private static final byte PROTOCOL_VERSION = (byte) 0x01;
58 55  
59   - // TODO @haohao:这个要不直接静态枚举,不用 MessageType
60 56 /**
61   - * 消息类型常量
  57 + * 请求消息类型
62 58 */
63   - public static class MessageType {
  59 + private static final byte REQUEST = (byte) 0x01;
64 60  
65   - /**
66   - * 请求消息
67   - */
68   - public static final byte REQUEST = 0x01;
69   - /**
70   - * 响应消息
71   - */
72   - public static final byte RESPONSE = 0x02;
73   -
74   - }
  61 + /**
  62 + * 响应消息类型
  63 + */
  64 + private static final byte RESPONSE = (byte) 0x02;
75 65  
76 66 /**
77   - * 协议头部固定长度(魔术字 + 版本号 + 消息类型 + 消息标志 + 消息长度)
  67 + * 协议头部固定长度(魔术字 + 版本号 + 消息类型 + 消息长度)
78 68 */
79   - private static final int HEADER_FIXED_LENGTH = 8;
  69 + private static final int HEADER_FIXED_LENGTH = 7;
80 70  
81 71 /**
82 72 * 最小消息长度(头部 + 消息ID长度 + 方法名长度)
... ... @@ -97,7 +87,7 @@ public class IotTcpBinaryDeviceMessageCodec implements IotDeviceMessageCodec {
97 87 byte messageType = determineMessageType(message);
98 88 // 2. 构建消息体
99 89 byte[] bodyData = buildMessageBody(message, messageType);
100   - // 3. 构建完整消息(不包含deviceId,由连接上下文管理)
  90 + // 3. 构建完整消息
101 91 return buildCompleteMessage(message, messageType, bodyData);
102 92 } catch (Exception e) {
103 93 log.error("[encode][TCP 二进制消息编码失败,消息: {}]", message, e);
... ... @@ -111,30 +101,59 @@ public class IotTcpBinaryDeviceMessageCodec implements IotDeviceMessageCodec {
111 101 Assert.isTrue(bytes.length >= MIN_MESSAGE_LENGTH, "数据包长度不足");
112 102 try {
113 103 Buffer buffer = Buffer.buffer(bytes);
114   - // 1. 解析协议头部
115   - ProtocolHeader header = parseProtocolHeader(buffer);
116   - // 2. 解析消息内容(不包含deviceId,由上层连接管理器设置)
117   - return parseMessageContent(buffer, header);
  104 + // 解析协议头部和消息内容
  105 + int index = 0;
  106 + // 1. 验证魔术字
  107 + byte magic = buffer.getByte(index++);
  108 + Assert.isTrue(magic == MAGIC_NUMBER, "无效的协议魔术字: " + magic);
  109 +
  110 + // 2. 验证版本号
  111 + byte version = buffer.getByte(index++);
  112 + Assert.isTrue(version == PROTOCOL_VERSION, "不支持的协议版本: " + version);
  113 +
  114 + // 3. 读取消息类型
  115 + byte messageType = buffer.getByte(index++);
  116 + // 直接验证消息类型,无需抽取方法
  117 + Assert.isTrue(messageType == REQUEST || messageType == RESPONSE,
  118 + "无效的消息类型: " + messageType);
  119 +
  120 + // 4. 读取消息长度
  121 + int messageLength = buffer.getInt(index);
  122 + index += 4;
  123 + Assert.isTrue(messageLength == buffer.length(),
  124 + "消息长度不匹配,期望: " + messageLength + ", 实际: " + buffer.length());
  125 +
  126 + // 5. 读取消息 ID
  127 + short messageIdLength = buffer.getShort(index);
  128 + index += 2;
  129 + String messageId = buffer.getString(index, index + messageIdLength, StandardCharsets.UTF_8.name());
  130 + index += messageIdLength;
  131 +
  132 + // 6. 读取方法名
  133 + short methodLength = buffer.getShort(index);
  134 + index += 2;
  135 + String method = buffer.getString(index, index + methodLength, StandardCharsets.UTF_8.name());
  136 + index += methodLength;
  137 +
  138 + // 7. 解析消息体
  139 + return parseMessageBody(buffer, index, messageType, messageId, method);
118 140 } catch (Exception e) {
119 141 log.error("[decode][TCP 二进制消息解码失败,数据长度: {}]", bytes.length, e);
120 142 throw new RuntimeException("TCP 二进制消息解码失败: " + e.getMessage(), e);
121 143 }
122 144 }
123 145  
124   - // ==================== 编码相关方法 ====================
125   -
126 146 /**
127 147 * 确定消息类型
128 148 * 优化后的判断逻辑:有响应字段就是响应消息,否则就是请求消息
129 149 */
130 150 private byte determineMessageType(IotDeviceMessage message) {
131 151 // 判断是否为响应消息:有响应码或响应消息时为响应
132   - // TODO @haohao:感觉只判断 code 更稳妥点?msg 有可能空。。。
133   - if (message.getCode() != null || StrUtil.isNotBlank(message.getMsg())) {
134   - return MessageType.RESPONSE;
  152 + if (message.getCode() != null) {
  153 + return RESPONSE;
135 154 }
136 155 // 默认为请求消息
137   - return MessageType.REQUEST;
  156 + return REQUEST;
138 157 }
139 158  
140 159 /**
... ... @@ -142,12 +161,12 @@ public class IotTcpBinaryDeviceMessageCodec implements IotDeviceMessageCodec {
142 161 */
143 162 private byte[] buildMessageBody(IotDeviceMessage message, byte messageType) {
144 163 Buffer bodyBuffer = Buffer.buffer();
145   - if (messageType == MessageType.RESPONSE) {
  164 + if (messageType == RESPONSE) {
146 165 // code
147 166 bodyBuffer.appendInt(message.getCode() != null ? message.getCode() : 0);
148 167 // msg
149 168 String msg = message.getMsg() != null ? message.getMsg() : "";
150   - byte[] msgBytes = msg.getBytes(StandardCharsets.UTF_8);
  169 + byte[] msgBytes = StrUtil.utf8Bytes(msg);
151 170 bodyBuffer.appendShort((short) msgBytes.length);
152 171 bodyBuffer.appendBytes(msgBytes);
153 172 // data
... ... @@ -155,11 +174,9 @@ public class IotTcpBinaryDeviceMessageCodec implements IotDeviceMessageCodec {
155 174 bodyBuffer.appendBytes(JsonUtils.toJsonByte(message.getData()));
156 175 }
157 176 } else {
158   - // params
159   - // TODO @haohao:请求是不是只处理 message.getParams() 哈?
160   - Object payload = message.getParams() != null ? message.getParams() : message.getData();
161   - if (payload != null) {
162   - bodyBuffer.appendBytes(JsonUtils.toJsonByte(payload));
  177 + // 请求消息只处理 params 参数
  178 + if (message.getParams() != null) {
  179 + bodyBuffer.appendBytes(JsonUtils.toJsonByte(message.getParams()));
163 180 }
164 181 }
165 182 return bodyBuffer.getBytes();
... ... @@ -174,20 +191,17 @@ public class IotTcpBinaryDeviceMessageCodec implements IotDeviceMessageCodec {
174 191 buffer.appendByte(MAGIC_NUMBER);
175 192 buffer.appendByte(PROTOCOL_VERSION);
176 193 buffer.appendByte(messageType);
177   - buffer.appendByte((byte) 0x00); // 消息标志,预留字段 TODO @haohao:这个标识的作用是啥呀?
178   - // 2. 预留消息长度位置(在 6. 更新消息长度)
  194 + // 2. 预留消息长度位置(在 5. 更新消息长度)
179 195 int lengthPosition = buffer.length();
180 196 buffer.appendInt(0);
181 197 // 3. 写入消息 ID
182 198 String messageId = StrUtil.isNotBlank(message.getRequestId()) ? message.getRequestId()
183   - // TODO @haohao:复用 IotDeviceMessageUtils 的 generateMessageId 哇?
184   - : generateMessageId(message.getMethod());
185   - // TODO @haohao:StrUtil.utf8Bytes()
186   - byte[] messageIdBytes = messageId.getBytes(StandardCharsets.UTF_8);
  199 + : IotDeviceMessageUtils.generateMessageId();
  200 + byte[] messageIdBytes = StrUtil.utf8Bytes(messageId);
187 201 buffer.appendShort((short) messageIdBytes.length);
188 202 buffer.appendBytes(messageIdBytes);
189 203 // 4. 写入方法名
190   - byte[] methodBytes = message.getMethod().getBytes(StandardCharsets.UTF_8);
  204 + byte[] methodBytes = StrUtil.utf8Bytes(message.getMethod());
191 205 buffer.appendShort((short) methodBytes.length);
192 206 buffer.appendBytes(methodBytes);
193 207 // 5. 写入消息体
... ... @@ -198,66 +212,6 @@ public class IotTcpBinaryDeviceMessageCodec implements IotDeviceMessageCodec {
198 212 }
199 213  
200 214 /**
201   - * 生成消息 ID
202   - */
203   - private String generateMessageId(String method) {
204   - return method + "_" + System.currentTimeMillis() + "_" + (int) (Math.random() * 1000);
205   - }
206   -
207   - // ==================== 解码相关方法 ====================
208   -
209   - // TODO @haohao:是不是把 parseProtocolHeader、parseMessageContent 合并?
210   - /**
211   - * 解析协议头部
212   - */
213   - private ProtocolHeader parseProtocolHeader(Buffer buffer) {
214   - int index = 0;
215   - // 1. 验证魔术字
216   - byte magic = buffer.getByte(index++);
217   - Assert.isTrue(magic == MAGIC_NUMBER, "无效的协议魔术字: " + magic);
218   - // 2. 验证版本号
219   - byte version = buffer.getByte(index++);
220   - Assert.isTrue(version == PROTOCOL_VERSION, "不支持的协议版本: " + version);
221   -
222   - // 3. 读取消息类型
223   - byte messageType = buffer.getByte(index++);
224   - Assert.isTrue(isValidMessageType(messageType), "无效的消息类型: " + messageType);
225   - // 4. 读取消息标志(暂时跳过)
226   - byte messageFlags = buffer.getByte(index++);
227   -
228   - // 5. 读取消息长度
229   - int messageLength = buffer.getInt(index);
230   - index += 4;
231   -
232   - Assert.isTrue(messageLength == buffer.length(),
233   - "消息长度不匹配,期望: " + messageLength + ", 实际: " + buffer.length());
234   -
235   - return new ProtocolHeader(magic, version, messageType, messageFlags, messageLength, index);
236   - }
237   -
238   - /**
239   - * 解析消息内容
240   - */
241   - private IotDeviceMessage parseMessageContent(Buffer buffer, ProtocolHeader header) {
242   - int index = header.getNextIndex();
243   -
244   - // 1. 读取消息 ID
245   - short messageIdLength = buffer.getShort(index);
246   - index += 2;
247   - String messageId = buffer.getString(index, index + messageIdLength, StandardCharsets.UTF_8.name());
248   - index += messageIdLength;
249   -
250   - // 2. 读取方法名
251   - short methodLength = buffer.getShort(index);
252   - index += 2;
253   - String method = buffer.getString(index, index + methodLength, StandardCharsets.UTF_8.name());
254   - index += methodLength;
255   -
256   - // 3. 解析消息体
257   - return parseMessageBody(buffer, index, header.getMessageType(), messageId, method);
258   - }
259   -
260   - /**
261 215 * 解析消息体
262 216 */
263 217 private IotDeviceMessage parseMessageBody(Buffer buffer, int startIndex, byte messageType,
... ... @@ -267,11 +221,11 @@ public class IotTcpBinaryDeviceMessageCodec implements IotDeviceMessageCodec {
267 221 return IotDeviceMessage.of(messageId, method, null, null, null, null);
268 222 }
269 223  
270   - if (messageType == MessageType.RESPONSE) {
  224 + if (messageType == RESPONSE) {
271 225 // 响应消息:解析 code + msg + data
272 226 return parseResponseMessage(buffer, startIndex, messageId, method);
273 227 } else {
274   - // 请求消息:解析 payload(可能是 params 或 data)
  228 + // 请求消息:解析 payload
275 229 Object payload = parseJsonData(buffer, startIndex, buffer.length());
276 230 return IotDeviceMessage.of(messageId, method, payload, null, null, null);
277 231 }
... ... @@ -303,7 +257,7 @@ public class IotTcpBinaryDeviceMessageCodec implements IotDeviceMessageCodec {
303 257 }
304 258  
305 259 /**
306   - * 解析JSON数据
  260 + * 解析 JSON 数据
307 261 */
308 262 private Object parseJsonData(Buffer buffer, int startIndex, int endIndex) {
309 263 if (startIndex >= endIndex) {
... ... @@ -318,34 +272,14 @@ public class IotTcpBinaryDeviceMessageCodec implements IotDeviceMessageCodec {
318 272 }
319 273 }
320 274  
321   - // ==================== 辅助方法 ====================
322   -
323   - // TODO @haohao:这个貌似只用一次,可以考虑不抽小方法哈;
324 275 /**
325   - * 验证消息类型是否有效
  276 + * 快速检测是否为二进制格式
  277 + *
  278 + * @param data 数据
  279 + * @return 是否为二进制格式
326 280 */
327   - private boolean isValidMessageType(byte messageType) {
328   - return messageType == MessageType.REQUEST || messageType == MessageType.RESPONSE;
  281 + public static boolean isBinaryFormatQuick(byte[] data) {
  282 + return data != null && data.length >= 1 && data[0] == MAGIC_NUMBER;
329 283 }
330 284  
331   - // ==================== 内部类 ====================
332   -
333   - /**
334   - * 协议头部信息
335   - */
336   - @Data
337   - @AllArgsConstructor
338   - private static class ProtocolHeader {
339   -
340   - private byte magic;
341   - private byte version;
342   - private byte messageType;
343   - private byte messageFlags;
344   - private int messageLength;
345   - /**
346   - * 指向消息内容开始位置
347   - */
348   - private int nextIndex;
349   -
350   - }
351 285 }
352 286 \ No newline at end of file
... ...
yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/tcp/manager/IotTcpConnectionManager.java
... ... @@ -28,46 +28,33 @@ public class IotTcpConnectionManager {
28 28 private final Map<NetSocket, ConnectionInfo> connectionMap = new ConcurrentHashMap<>();
29 29  
30 30 /**
31   - * 设备 ID -> NetSocket 的映射(用于快速查找)
  31 + * 设备 ID -> NetSocket 的映射
32 32 */
33 33 private final Map<Long, NetSocket> deviceSocketMap = new ConcurrentHashMap<>();
34 34  
35 35 /**
36   - * NetSocket -> 设备 ID 的映射(用于连接断开时清理)
37   - */
38   - private final Map<NetSocket, Long> socketDeviceMap = new ConcurrentHashMap<>();
39   -
40   - /**
41 36 * 注册设备连接(包含认证信息)
42 37 *
43   - * @param socket TCP 连接
44   - * @param deviceId 设备 ID
45   - * @param authInfo 认证信息
  38 + * @param socket TCP 连接
  39 + * @param deviceId 设备 ID
  40 + * @param connectionInfo 连接信息
46 41 */
47   - public void registerConnection(NetSocket socket, Long deviceId, AuthInfo authInfo) {
  42 + public void registerConnection(NetSocket socket, Long deviceId, ConnectionInfo connectionInfo) {
48 43 // 如果设备已有其他连接,先清理旧连接
49 44 NetSocket oldSocket = deviceSocketMap.get(deviceId);
50 45 if (oldSocket != null && oldSocket != socket) {
51 46 log.info("[registerConnection][设备已有其他连接,断开旧连接,设备 ID: {},旧连接: {}]",
52 47 deviceId, oldSocket.remoteAddress());
53 48 oldSocket.close();
54   - // 清理所有相关映射
  49 + // 清理旧连接的映射
55 50 connectionMap.remove(oldSocket);
56   - socketDeviceMap.remove(oldSocket);
57 51 }
58 52  
59   - // 注册新连接 - 更新所有映射关系
60   - ConnectionInfo connectionInfo = new ConnectionInfo()
61   - .setDeviceId(deviceId)
62   - .setAuthInfo(authInfo)
63   - .setAuthenticated(true);
64 53 connectionMap.put(socket, connectionInfo);
65 54 deviceSocketMap.put(deviceId, socket);
66   - // TODO @haohao:socketDeviceMap 和 connectionMap 会重复哇?connectionMap.get(socket).getDeviceId
67   - socketDeviceMap.put(socket, deviceId);
68 55  
69 56 log.info("[registerConnection][注册设备连接,设备 ID: {},连接: {},product key: {},device name: {}]",
70   - deviceId, socket.remoteAddress(), authInfo.getProductKey(), authInfo.getDeviceName());
  57 + deviceId, socket.remoteAddress(), connectionInfo.getProductKey(), connectionInfo.getDeviceName());
71 58 }
72 59  
73 60 /**
... ... @@ -77,29 +64,14 @@ public class IotTcpConnectionManager {
77 64 */
78 65 public void unregisterConnection(NetSocket socket) {
79 66 ConnectionInfo connectionInfo = connectionMap.remove(socket);
80   - Long deviceId = socketDeviceMap.remove(socket);
81   - if (connectionInfo != null && deviceId != null) {
  67 + if (connectionInfo != null) {
  68 + Long deviceId = connectionInfo.getDeviceId();
82 69 deviceSocketMap.remove(deviceId);
83 70 log.info("[unregisterConnection][注销设备连接,设备 ID: {},连接: {}]",
84 71 deviceId, socket.remoteAddress());
85 72 }
86 73 }
87 74  
88   - // TODO @haohao:用不到,要不暂时清理哈。
89   - /**
90   - * 注销设备连接(通过设备 ID)
91   - *
92   - * @param deviceId 设备 ID
93   - */
94   - public void unregisterConnection(Long deviceId) {
95   - NetSocket socket = deviceSocketMap.remove(deviceId);
96   - if (socket != null) {
97   - connectionMap.remove(socket);
98   - socketDeviceMap.remove(socket);
99   - log.info("[unregisterConnection][注销设备连接,设备 ID: {},连接: {}]", deviceId, socket.remoteAddress());
100   - }
101   - }
102   -
103 75 /**
104 76 * 检查连接是否已认证
105 77 */
... ... @@ -116,11 +88,10 @@ public class IotTcpConnectionManager {
116 88 }
117 89  
118 90 /**
119   - * 获取连接的认证信息
  91 + * 获取连接信息
120 92 */
121   - public AuthInfo getAuthInfo(NetSocket socket) {
122   - ConnectionInfo info = connectionMap.get(socket);
123   - return info != null ? info.getAuthInfo() : null;
  93 + public ConnectionInfo getConnectionInfo(NetSocket socket) {
  94 + return connectionMap.get(socket);
124 95 }
125 96  
126 97 /**
... ... @@ -159,30 +130,34 @@ public class IotTcpConnectionManager {
159 130 }
160 131 }
161 132  
162   - // TODO @haohao:ConnectionInfo 和 AuthInfo 是不是可以融合哈?
163   -
164 133 /**
165   - * 连接信息
  134 + * 连接信息(包含认证信息)
166 135 */
167 136 @Data
168 137 public static class ConnectionInfo {
169   -
170   - private Long deviceId;
171   - private AuthInfo authInfo;
172   - private boolean authenticated;
173   -
174   - }
175   -
176   - /**
177   - * 认证信息
178   - */
179   - @Data
180   - public static class AuthInfo {
181   -
  138 + /**
  139 + * 设备 ID
  140 + */
182 141 private Long deviceId;
  142 + /**
  143 + * 产品 Key
  144 + */
183 145 private String productKey;
  146 + /**
  147 + * 设备名称
  148 + */
184 149 private String deviceName;
  150 + /**
  151 + * 客户端 ID
  152 + */
185 153 private String clientId;
186   -
  154 + /**
  155 + * 消息编解码类型(认证后确定)
  156 + */
  157 + private String codecType;
  158 + /**
  159 + * 是否已认证
  160 + */
  161 + private boolean authenticated;
187 162 }
188 163 }
189 164 \ No newline at end of file
... ...
yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/tcp/router/IotTcpUpstreamHandler.java
1 1 package cn.iocoder.yudao.module.iot.gateway.protocol.tcp.router;
2 2  
3 3 import cn.hutool.core.map.MapUtil;
  4 +import cn.hutool.core.util.BooleanUtil;
4 5 import cn.hutool.core.util.IdUtil;
5 6 import cn.hutool.core.util.StrUtil;
6 7 import cn.hutool.extra.spring.SpringUtil;
7   -import cn.hutool.json.JSONObject;
8   -import cn.hutool.json.JSONUtil;
9 8 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
  9 +import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
10 10 import cn.iocoder.yudao.module.iot.core.biz.IotDeviceCommonApi;
11 11 import cn.iocoder.yudao.module.iot.core.biz.dto.IotDeviceAuthReqDTO;
12 12 import cn.iocoder.yudao.module.iot.core.biz.dto.IotDeviceRespDTO;
... ... @@ -21,12 +21,8 @@ import cn.iocoder.yudao.module.iot.gateway.service.device.message.IotDeviceMessa
21 21 import io.vertx.core.Handler;
22 22 import io.vertx.core.buffer.Buffer;
23 23 import io.vertx.core.net.NetSocket;
24   -import lombok.AllArgsConstructor;
25   -import lombok.Data;
26 24 import lombok.extern.slf4j.Slf4j;
27 25  
28   -import java.nio.charset.StandardCharsets;
29   -
30 26 /**
31 27 * TCP 上行消息处理器
32 28 *
... ... @@ -77,31 +73,55 @@ public class IotTcpUpstreamHandler implements Handler&lt;NetSocket&gt; {
77 73 });
78 74  
79 75 // 设置消息处理器
80   - socket.handler(buffer -> processMessage(clientId, buffer, socket));
  76 + socket.handler(buffer -> {
  77 + try {
  78 + processMessage(clientId, buffer, socket);
  79 + } catch (Exception e) {
  80 + log.error("[handle][消息解码失败,断开连接,客户端 ID: {},地址: {},错误: {}]",
  81 + clientId, socket.remoteAddress(), e.getMessage());
  82 + cleanupConnection(socket);
  83 + socket.close();
  84 + }
  85 + });
81 86 }
82 87  
83 88 /**
84 89 * 处理消息
  90 + *
  91 + * @param clientId 客户端 ID
  92 + * @param buffer 消息
  93 + * @param socket 网络连接
  94 + * @throws Exception 消息解码失败时抛出异常
85 95 */
86   - private void processMessage(String clientId, Buffer buffer, NetSocket socket) {
  96 + private void processMessage(String clientId, Buffer buffer, NetSocket socket) throws Exception {
  97 + // 1. 基础检查
  98 + if (buffer == null || buffer.length() == 0) {
  99 + return;
  100 + }
  101 +
  102 + // 2. 获取消息格式类型
  103 + String codecType = getMessageCodecType(buffer, socket);
  104 +
  105 + // 3. 解码消息
  106 + IotDeviceMessage message;
87 107 try {
88   - // 1.1 数据包基础检查
89   - if (buffer.length() == 0) {
90   - return;
91   - }
92   - // 1.2 解码消息
93   - MessageInfo messageInfo = decodeMessage(buffer);
94   - if (messageInfo == null) {
95   - return;
  108 + message = deviceMessageService.decodeDeviceMessage(buffer.getBytes(), codecType);
  109 + if (message == null) {
  110 + throw new Exception("解码后消息为空");
96 111 }
  112 + } catch (Exception e) {
  113 + // 消息格式错误时抛出异常,由上层处理连接断开
  114 + throw new Exception("消息解码失败: " + e.getMessage(), e);
  115 + }
97 116  
98   - // 2. 根据消息类型路由处理
99   - if (isAuthRequest(messageInfo.message)) {
  117 + // 4. 根据消息类型路由处理
  118 + try {
  119 + if (AUTH_METHOD.equals(message.getMethod())) {
100 120 // 认证请求
101   - handleAuthenticationRequest(clientId, messageInfo, socket);
  121 + handleAuthenticationRequest(clientId, message, codecType, socket);
102 122 } else {
103 123 // 业务消息
104   - handleBusinessRequest(clientId, messageInfo, socket);
  124 + handleBusinessRequest(clientId, message, codecType, socket);
105 125 }
106 126 } catch (Exception e) {
107 127 log.error("[processMessage][处理消息失败,客户端 ID: {}]", clientId, e);
... ... @@ -110,226 +130,158 @@ public class IotTcpUpstreamHandler implements Handler&lt;NetSocket&gt; {
110 130  
111 131 /**
112 132 * 处理认证请求
  133 + *
  134 + * @param clientId 客户端 ID
  135 + * @param message 消息信息
  136 + * @param codecType 消息编解码类型
  137 + * @param socket 网络连接
113 138 */
114   - private void handleAuthenticationRequest(String clientId, MessageInfo messageInfo, NetSocket socket) {
  139 + private void handleAuthenticationRequest(String clientId, IotDeviceMessage message, String codecType,
  140 + NetSocket socket) {
115 141 try {
116 142 // 1.1 解析认证参数
117   - IotDeviceMessage message = messageInfo.message;
118   - AuthParams authParams = parseAuthParams(message.getParams());
  143 + IotDeviceAuthReqDTO authParams = JsonUtils.parseObject(message.getParams().toString(),
  144 + IotDeviceAuthReqDTO.class);
119 145 if (authParams == null) {
120   - sendError(socket, message.getRequestId(), "认证参数不完整", messageInfo.codecType);
  146 + sendErrorResponse(socket, message.getRequestId(), "认证参数不完整", codecType);
121 147 return;
122 148 }
123 149 // 1.2 执行认证
124   - if (!authenticateDevice(authParams)) {
  150 + if (!validateDeviceAuth(authParams)) {
125 151 log.warn("[handleAuthenticationRequest][认证失败,客户端 ID: {},username: {}]",
126   - clientId, authParams.username);
127   - sendError(socket, message.getRequestId(), "认证失败", messageInfo.codecType);
  152 + clientId, authParams.getUsername());
  153 + sendErrorResponse(socket, message.getRequestId(), "认证失败", codecType);
128 154 return;
129 155 }
130 156  
131 157 // 2.1 解析设备信息
132   - IotDeviceAuthUtils.DeviceInfo deviceInfo = IotDeviceAuthUtils.parseUsername(authParams.username);
  158 + IotDeviceAuthUtils.DeviceInfo deviceInfo = IotDeviceAuthUtils.parseUsername(authParams.getUsername());
133 159 if (deviceInfo == null) {
134   - sendError(socket, message.getRequestId(), "解析设备信息失败", messageInfo.codecType);
  160 + sendErrorResponse(socket, message.getRequestId(), "解析设备信息失败", codecType);
135 161 return;
136 162 }
137 163 // 2.2 获取设备信息
138 164 IotDeviceRespDTO device = deviceService.getDeviceFromCache(deviceInfo.getProductKey(),
139 165 deviceInfo.getDeviceName());
140 166 if (device == null) {
141   - sendError(socket, message.getRequestId(), "设备不存在", messageInfo.codecType);
  167 + sendErrorResponse(socket, message.getRequestId(), "设备不存在", codecType);
142 168 return;
143 169 }
144 170  
145   - // 3. 注册连接并发送成功响应
146   - registerConnection(socket, device, deviceInfo, authParams.clientId);
147   - sendOnlineMessage(deviceInfo);
148   - sendSuccess(socket, message.getRequestId(), "认证成功", messageInfo.codecType);
  171 + // 3.1 注册连接
  172 + registerConnection(socket, device, clientId, codecType);
  173 + // 3.2 发送上线消息
  174 + sendOnlineMessage(device);
  175 + // 3.3 发送成功响应
  176 + sendSuccessResponse(socket, message.getRequestId(), "认证成功", codecType);
149 177 log.info("[handleAuthenticationRequest][认证成功,设备 ID: {},设备名: {}]",
150   - device.getId(), deviceInfo.getDeviceName());
  178 + device.getId(), device.getDeviceName());
151 179 } catch (Exception e) {
152 180 log.error("[handleAuthenticationRequest][认证处理异常,客户端 ID: {}]", clientId, e);
153   - sendError(socket, messageInfo.message.getRequestId(), "认证处理异常", messageInfo.codecType);
  181 + sendErrorResponse(socket, message.getRequestId(), "认证处理异常", codecType);
154 182 }
155 183 }
156 184  
157 185 /**
158 186 * 处理业务请求
  187 + *
  188 + * @param clientId 客户端 ID
  189 + * @param message 消息信息
  190 + * @param codecType 消息编解码类型
  191 + * @param socket 网络连接
159 192 */
160   - private void handleBusinessRequest(String clientId, MessageInfo messageInfo, NetSocket socket) {
  193 + private void handleBusinessRequest(String clientId, IotDeviceMessage message, String codecType, NetSocket socket) {
161 194 try {
162 195 // 1. 检查认证状态
163 196 if (connectionManager.isNotAuthenticated(socket)) {
164 197 log.warn("[handleBusinessRequest][设备未认证,客户端 ID: {}]", clientId);
165   - sendError(socket, messageInfo.message.getRequestId(), "请先进行认证", messageInfo.codecType);
  198 + sendErrorResponse(socket, message.getRequestId(), "请先进行认证", codecType);
166 199 return;
167 200 }
168 201  
169 202 // 2. 获取认证信息并处理业务消息
170   - IotTcpConnectionManager.AuthInfo authInfo = connectionManager.getAuthInfo(socket);
171   - processBusinessMessage(clientId, messageInfo.message, authInfo);
172   - } catch (Exception e) {
173   - log.error("[handleBusinessRequest][业务请求处理异常,客户端 ID: {}]", clientId, e);
174   - }
175   - }
  203 + IotTcpConnectionManager.ConnectionInfo connectionInfo = connectionManager.getConnectionInfo(socket);
176 204  
177   - // TODO @haohao:processBusinessMessage 这个小方法,直接融合到 handleBusinessRequest 里?读起来更聚集点
178   - /**
179   - * 处理业务消息
180   - */
181   - private void processBusinessMessage(String clientId, IotDeviceMessage message,
182   - IotTcpConnectionManager.AuthInfo authInfo) {
183   - try {
184   - message.setDeviceId(authInfo.getDeviceId());
185   - message.setServerId(serverId);
186   - // 发送到消息总线
187   - deviceMessageService.sendDeviceMessage(message, authInfo.getProductKey(),
188   - authInfo.getDeviceName(), serverId);
  205 + // 3. 发送消息到消息总线
  206 + deviceMessageService.sendDeviceMessage(message, connectionInfo.getProductKey(),
  207 + connectionInfo.getDeviceName(), serverId);
189 208 } catch (Exception e) {
190   - log.error("[processBusinessMessage][业务消息处理失败,客户端 ID: {},消息 ID: {}]",
191   - clientId, message.getId(), e);
  209 + log.error("[handleBusinessRequest][业务请求处理异常,客户端 ID: {}]", clientId, e);
192 210 }
193 211 }
194 212  
195 213 /**
196   - * 解码消息
  214 + * 获取消息编解码类型
197 215 *
198 216 * @param buffer 消息
  217 + * @param socket 网络连接
  218 + * @return 消息编解码类型
199 219 */
200   - private MessageInfo decodeMessage(Buffer buffer) {
201   - if (buffer == null || buffer.length() == 0) {
202   - return null;
203   - }
204   - // 1. 快速检测消息格式类型
205   - // TODO @haohao:是不是进一步优化?socket 建立认证后,那条消息已经定义了所有消息的格式哈?
206   - String codecType = detectMessageFormat(buffer);
207   - try {
208   - // 2. 使用检测到的格式进行解码
209   - IotDeviceMessage message = deviceMessageService.decodeDeviceMessage(buffer.getBytes(), codecType);
210   - if (message == null) {
211   - return null;
212   - }
213   - return new MessageInfo(message, codecType);
214   - } catch (Exception e) {
215   - log.warn("[decodeMessage][消息解码失败,格式: {},数据长度: {},错误: {}]",
216   - codecType, buffer.length(), e.getMessage());
217   - // TODO @haohao:一般消息格式不对,应该抛出异常,断开连接居多?
218   - return null;
219   - }
220   - }
221   -
222   - /**
223   - * 检测消息格式类型
224   - * 优化性能:避免不必要的字符串转换
225   - */
226   - private String detectMessageFormat(Buffer buffer) {
227   - // TODO @haohao:是不是 IotTcpBinaryDeviceMessageCodec 提供一个 isBinaryFormat 方法哈?
228   - // 默认使用 JSON
229   - if (buffer.length() == 0) {
230   - return CODEC_TYPE_JSON;
231   - }
232   -
233   - // 1. 优先检测二进制格式(检查魔术字节 0x7E)
234   - if (isBinaryFormat(buffer)) {
235   - return CODEC_TYPE_BINARY;
236   - }
237   -
238   - // 2. 检测 JSON 格式(检查前几个有效字符)
239   - // TODO @haohao:这个检测去掉?直接 return CODEC_TYPE_JSON 更简洁一点。
240   - if (isJsonFormat(buffer)) {
241   - return CODEC_TYPE_JSON;
  220 + private String getMessageCodecType(Buffer buffer, NetSocket socket) {
  221 + // 1. 如果已认证,优先使用缓存的编解码类型
  222 + IotTcpConnectionManager.ConnectionInfo connectionInfo = connectionManager.getConnectionInfo(socket);
  223 + if (connectionInfo != null && connectionInfo.isAuthenticated() &&
  224 + StrUtil.isNotBlank(connectionInfo.getCodecType())) {
  225 + return connectionInfo.getCodecType();
242 226 }
243 227  
244   - // 3. 默认尝试 JSON 格式
245   - return CODEC_TYPE_JSON;
246   - }
247   -
248   - /**
249   - * 检测二进制格式
250   - * 通过检查魔术字节快速识别,避免完整字符串转换
251   - */
252   - private boolean isBinaryFormat(Buffer buffer) {
253   - // 二进制协议最小长度检查
254   - if (buffer.length() < 8) {
255   - return false;
256   - }
257   -
258   - try {
259   - // 检查魔术字节 0x7E(二进制协议的第一个字节)
260   - byte firstByte = buffer.getByte(0);
261   - return firstByte == (byte) 0x7E;
262   - } catch (Exception e) {
263   - return false;
264   - }
265   - }
266   -
267   - /**
268   - * 检测 JSON 格式
269   - * 只检查前几个有效字符,避免完整字符串转换
270   - */
271   - private boolean isJsonFormat(Buffer buffer) {
272   - try {
273   - // 检查前 64 个字节或整个缓冲区(取较小值)
274   - int checkLength = Math.min(buffer.length(), 64);
275   - String prefix = buffer.getString(0, checkLength, StandardCharsets.UTF_8.name());
276   -
277   - if (StrUtil.isBlank(prefix)) {
278   - return false;
279   - }
280   -
281   - String trimmed = prefix.trim();
282   - // JSON 格式必须以 { 或 [ 开头
283   - return trimmed.startsWith("{") || trimmed.startsWith("[");
284   -
285   - } catch (Exception e) {
286   - return false;
287   - }
  228 + // 2. 未认证时检测消息格式类型
  229 + return IotTcpBinaryDeviceMessageCodec.isBinaryFormatQuick(buffer.getBytes()) ? CODEC_TYPE_BINARY
  230 + : CODEC_TYPE_JSON;
288 231 }
289 232  
290 233 /**
291 234 * 注册连接信息
  235 + *
  236 + * @param socket 网络连接
  237 + * @param device 设备
  238 + * @param clientId 客户端 ID
  239 + * @param codecType 消息编解码类型
292 240 */
293 241 private void registerConnection(NetSocket socket, IotDeviceRespDTO device,
294   - IotDeviceAuthUtils.DeviceInfo deviceInfo, String clientId) {
295   - // TODO @haohao:AuthInfo 的创建,放在 connectionManager 里构建貌似会更收敛一点?
296   - // 创建认证信息
297   - IotTcpConnectionManager.AuthInfo authInfo = new IotTcpConnectionManager.AuthInfo()
  242 + String clientId, String codecType) {
  243 + IotTcpConnectionManager.ConnectionInfo connectionInfo = new IotTcpConnectionManager.ConnectionInfo()
298 244 .setDeviceId(device.getId())
299   - .setProductKey(deviceInfo.getProductKey())
300   - .setDeviceName(deviceInfo.getDeviceName())
301   - .setClientId(clientId);
  245 + .setProductKey(device.getProductKey())
  246 + .setDeviceName(device.getDeviceName())
  247 + .setClientId(clientId)
  248 + .setCodecType(codecType)
  249 + .setAuthenticated(true);
302 250 // 注册连接
303   - connectionManager.registerConnection(socket, device.getId(), authInfo);
  251 + connectionManager.registerConnection(socket, device.getId(), connectionInfo);
304 252 }
305 253  
306 254 /**
307 255 * 发送设备上线消息
  256 + *
  257 + * @param device 设备信息
308 258 */
309   - private void sendOnlineMessage(IotDeviceAuthUtils.DeviceInfo deviceInfo) {
  259 + private void sendOnlineMessage(IotDeviceRespDTO device) {
310 260 try {
311 261 IotDeviceMessage onlineMessage = IotDeviceMessage.buildStateUpdateOnline();
312   - deviceMessageService.sendDeviceMessage(onlineMessage, deviceInfo.getProductKey(),
313   - deviceInfo.getDeviceName(), serverId);
  262 + deviceMessageService.sendDeviceMessage(onlineMessage, device.getProductKey(),
  263 + device.getDeviceName(), serverId);
314 264 } catch (Exception e) {
315   - log.error("[sendOnlineMessage][发送上线消息失败,设备: {}]", deviceInfo.getDeviceName(), e);
  265 + log.error("[sendOnlineMessage][发送上线消息失败,设备: {}]", device.getDeviceName(), e);
316 266 }
317 267 }
318 268  
319 269 /**
320 270 * 清理连接
  271 + *
  272 + * @param socket 网络连接
321 273 */
322 274 private void cleanupConnection(NetSocket socket) {
323 275 try {
324   - // 发送离线消息(如果已认证)
325   - IotTcpConnectionManager.AuthInfo authInfo = connectionManager.getAuthInfo(socket);
326   - if (authInfo != null) {
  276 + // 1. 发送离线消息(如果已认证)
  277 + IotTcpConnectionManager.ConnectionInfo connectionInfo = connectionManager.getConnectionInfo(socket);
  278 + if (connectionInfo != null) {
327 279 IotDeviceMessage offlineMessage = IotDeviceMessage.buildStateOffline();
328   - deviceMessageService.sendDeviceMessage(offlineMessage, authInfo.getProductKey(),
329   - authInfo.getDeviceName(), serverId);
  280 + deviceMessageService.sendDeviceMessage(offlineMessage, connectionInfo.getProductKey(),
  281 + connectionInfo.getDeviceName(), serverId);
330 282 }
331 283  
332   - // 注销连接
  284 + // 2. 注销连接
333 285 connectionManager.unregisterConnection(socket);
334 286 } catch (Exception e) {
335 287 log.error("[cleanupConnection][清理连接失败]", e);
... ... @@ -338,6 +290,12 @@ public class IotTcpUpstreamHandler implements Handler&lt;NetSocket&gt; {
338 290  
339 291 /**
340 292 * 发送响应消息
  293 + *
  294 + * @param socket 网络连接
  295 + * @param success 是否成功
  296 + * @param message 消息
  297 + * @param requestId 请求 ID
  298 + * @param codecType 消息编解码类型
341 299 */
342 300 private void sendResponse(NetSocket socket, boolean success, String message, String requestId, String codecType) {
343 301 try {
... ... @@ -346,8 +304,9 @@ public class IotTcpUpstreamHandler implements Handler&lt;NetSocket&gt; {
346 304 .put("message", message)
347 305 .build();
348 306  
  307 + int code = success ? 0 : 401;
349 308 IotDeviceMessage responseMessage = IotDeviceMessage.replyOf(requestId, AUTH_METHOD, responseData,
350   - success ? 0 : 401, message);
  309 + code, message);
351 310  
352 311 byte[] encodedData = deviceMessageService.encodeDeviceMessage(responseMessage, codecType);
353 312 socket.write(Buffer.buffer(encodedData));
... ... @@ -357,94 +316,47 @@ public class IotTcpUpstreamHandler implements Handler&lt;NetSocket&gt; {
357 316 }
358 317 }
359 318  
360   - // ==================== 辅助方法 ====================
361   -
362   - /**
363   - * 判断是否为认证请求
364   - */
365   - private boolean isAuthRequest(IotDeviceMessage message) {
366   - return AUTH_METHOD.equals(message.getMethod());
367   - }
368   -
369   - /**
370   - * 解析认证参数
371   - */
372   - private AuthParams parseAuthParams(Object params) {
373   - if (params == null) {
374   - return null;
375   - }
376   - try {
377   - JSONObject paramsJson = params instanceof JSONObject ? (JSONObject) params
378   - : JSONUtil.parseObj(params.toString());
379   - String clientId = paramsJson.getStr("clientId");
380   - String username = paramsJson.getStr("username");
381   - String password = paramsJson.getStr("password");
382   - return StrUtil.hasBlank(clientId, username, password) ? null
383   - : new AuthParams(clientId, username, password);
384   - } catch (Exception e) {
385   - log.warn("[parseAuthParams][解析认证参数失败]", e);
386   - return null;
387   - }
388   - }
389   -
390 319 /**
391   - * 认证设备
  320 + * 验证设备认证信息
  321 + *
  322 + * @param authParams 认证参数
  323 + * @return 是否认证成功
392 324 */
393   - private boolean authenticateDevice(AuthParams authParams) {
  325 + private boolean validateDeviceAuth(IotDeviceAuthReqDTO authParams) {
394 326 try {
395 327 CommonResult<Boolean> result = deviceApi.authDevice(new IotDeviceAuthReqDTO()
396   - .setClientId(authParams.clientId)
397   - .setUsername(authParams.username)
398   - .setPassword(authParams.password));
399   - return result.isSuccess() && Boolean.TRUE.equals(result.getData());
  328 + .setClientId(authParams.getClientId()).setUsername(authParams.getUsername())
  329 + .setPassword(authParams.getPassword()));
  330 + result.checkError();
  331 + return BooleanUtil.isTrue(result.getData());
400 332 } catch (Exception e) {
401   - log.error("[authenticateDevice][设备认证异常,username: {}]", authParams.username, e);
  333 + log.error("[validateDeviceAuth][设备认证异常,username: {}]", authParams.getUsername(), e);
402 334 return false;
403 335 }
404 336 }
405 337  
406   - // TODO @haohao:改成 sendErrorResponse sendSuccessResponse 更清晰点?
407   -
408 338 /**
409 339 * 发送错误响应
  340 + *
  341 + * @param socket 网络连接
  342 + * @param requestId 请求 ID
  343 + * @param errorMessage 错误消息
  344 + * @param codecType 消息编解码类型
410 345 */
411   - private void sendError(NetSocket socket, String requestId, String errorMessage, String codecType) {
  346 + private void sendErrorResponse(NetSocket socket, String requestId, String errorMessage, String codecType) {
412 347 sendResponse(socket, false, errorMessage, requestId, codecType);
413 348 }
414 349  
415 350 /**
416 351 * 发送成功响应
  352 + *
  353 + * @param socket 网络连接
  354 + * @param requestId 请求 ID
  355 + * @param message 消息
  356 + * @param codecType 消息编解码类型
417 357 */
418   - private void sendSuccess(NetSocket socket, String requestId, String message, String codecType) {
  358 + private void sendSuccessResponse(NetSocket socket, String requestId, String message, String codecType) {
419 359 sendResponse(socket, true, message, requestId, codecType);
420 360 }
421 361  
422   - // ==================== 内部类 ====================
423   -
424   - // TODO @haohao:IotDeviceAuthReqDTO 复用这个?
425   - /**
426   - * 认证参数
427   - */
428   - @Data
429   - @AllArgsConstructor
430   - private static class AuthParams {
431   -
432   - private final String clientId;
433   - private final String username;
434   - private final String password;
435   -
436   - }
437   -
438   - /**
439   - * 消息信息
440   - */
441   - @Data
442   - @AllArgsConstructor
443   - private static class MessageInfo {
444   -
445   - private final IotDeviceMessage message;
446   -
447   - private final String codecType;
448   -
449   - }
450 362 }
451 363 \ No newline at end of file
... ...
yudao-module-iot/yudao-module-iot-gateway/src/test/resources/tcp-binary-packet-examples.md
... ... @@ -9,7 +9,7 @@ TCP 二进制å议是一ç§é«˜æ•ˆçš„自定义å议格å¼ï¼Œé‡‡ç”¨ç´§å‡‘的二è
9 9 - **高效传输**:完全二进制格å¼ï¼Œå‡å°‘æ•°æ®ä¼ è¾“é‡
10 10 - **版本控制**:内置å议版本å·ï¼Œæ”¯æŒåè®®å‡çº§
11 11 - **类型安全**:明确的消æ¯ç±»åž‹æ ‡è¯†
12   -- **扩展性**:预留标志ä½ï¼Œæ”¯æŒæœªæ¥åŠŸèƒ½æ‰©å±•
  12 +- **简æ´è®¾è®¡**:去除冗余字段,å议更加精简
13 13 - **兼容性**:与现有 `IotDeviceMessage` 接å£å®Œå…¨å…¼å®¹
14 14  
15 15 ## 2. å议格å¼
... ... @@ -17,9 +17,9 @@ TCP 二进制å议是一ç§é«˜æ•ˆçš„自定义å议格å¼ï¼Œé‡‡ç”¨ç´§å‡‘的二è
17 17 ### 2.1 整体结构
18 18  
19 19 ```
20   -+--------+--------+--------+--------+--------+--------+--------+--------+
21   -| 魔术字 | ç‰ˆæœ¬å· | 消æ¯ç±»åž‹| æ¶ˆæ¯æ ‡å¿—| 消æ¯é•¿åº¦(4字节) |
22   -+--------+--------+--------+--------+--------+--------+--------+--------+
  20 ++--------+--------+--------+---------------------------+--------+--------+
  21 +| 魔术字 | ç‰ˆæœ¬å· | 消æ¯ç±»åž‹| 消æ¯é•¿åº¦(4字节) |
  22 ++--------+--------+--------+---------------------------+--------+--------+
23 23 | æ¶ˆæ¯ ID 长度(2字节) | æ¶ˆæ¯ ID (å˜é•¿å­—符串) |
24 24 +--------+--------+--------+--------+--------+--------+--------+--------+
25 25 | 方法å长度(2字节) | 方法å(å˜é•¿å­—符串) |
... ... @@ -35,7 +35,6 @@ TCP 二进制å议是一ç§é«˜æ•ˆçš„自定义å议格å¼ï¼Œé‡‡ç”¨ç´§å‡‘的二è
35 35 | 魔术字 | 1字节 | byte | `0x7E` - å议识别标识,用于数æ®åŒæ­¥ |
36 36 | ç‰ˆæœ¬å· | 1字节 | byte | `0x01` - å议版本å·ï¼Œæ”¯æŒç‰ˆæœ¬æŽ§åˆ¶ |
37 37 | 消æ¯ç±»åž‹ | 1字节 | byte | `0x01`=请求, `0x02`=å“应 |
38   -| æ¶ˆæ¯æ ‡å¿— | 1字节 | byte | é¢„ç•™å­—æ®µï¼Œç”¨äºŽæœªæ¥æ‰©å±• |
39 38 | 消æ¯é•¿åº¦ | 4字节 | int | 整个消æ¯çš„æ€»é•¿åº¦ï¼ˆåŒ…å«å¤´éƒ¨ï¼‰ |
40 39 | æ¶ˆæ¯ ID 长度 | 2字节 | short | æ¶ˆæ¯ ID 字符串的字节长度 |
41 40 | æ¶ˆæ¯ ID | å˜é•¿ | string | 消æ¯å”¯ä¸€æ ‡è¯†ç¬¦ï¼ˆUTF-8ç¼–ç ï¼‰ |
... ... @@ -53,14 +52,12 @@ private static final byte MAGIC_NUMBER = (byte) 0x7E;
53 52 private static final byte PROTOCOL_VERSION = (byte) 0x01;
54 53  
55 54 // 消æ¯ç±»åž‹
56   -public static class MessageType {
57   - public static final byte REQUEST = 0x01; // 请求消æ¯
58   - public static final byte RESPONSE = 0x02; // å“应消æ¯
59   -}
  55 +private static final byte REQUEST = (byte) 0x01; // 请求消æ¯
  56 +private static final byte RESPONSE = (byte) 0x02; // å“应消æ¯
60 57  
61 58 // å议长度
62   -private static final int HEADER_FIXED_LENGTH = 8; // 固定头部长度
63   -private static final int MIN_MESSAGE_LENGTH = 12; // æœ€å°æ¶ˆæ¯é•¿åº¦
  59 +private static final int HEADER_FIXED_LENGTH = 7; // 固定头部长度
  60 +private static final int MIN_MESSAGE_LENGTH = 11; // æœ€å°æ¶ˆæ¯é•¿åº¦
64 61 ```
65 62  
66 63 ## 3. 消æ¯ç±»åž‹å’Œæ ¼å¼
... ... @@ -86,8 +83,7 @@ private static final int MIN_MESSAGE_LENGTH = 12; // æœ€å°æ¶ˆæ¯é•¿åº¦
86 83 7E // 魔术字 (0x7E)
87 84 01 // ç‰ˆæœ¬å· (0x01)
88 85 01 // 消æ¯ç±»åž‹ (REQUEST)
89   -00 // æ¶ˆæ¯æ ‡å¿— (预留)
90   -00 00 00 8A // 消æ¯é•¿åº¦ (138字节)
  86 +00 00 00 89 // 消æ¯é•¿åº¦ (137字节)
91 87 00 19 // æ¶ˆæ¯ ID 长度 (25字节)
92 88 61 75 74 68 5F 31 37 30 34 30 // æ¶ˆæ¯ ID: "auth_1704067200000_123"
93 89 36 37 32 30 30 30 30 30 5F 31
... ... @@ -144,8 +140,7 @@ private static final int MIN_MESSAGE_LENGTH = 12; // æœ€å°æ¶ˆæ¯é•¿åº¦
144 140 7E // 魔术字 (0x7E)
145 141 01 // ç‰ˆæœ¬å· (0x01)
146 142 02 // 消æ¯ç±»åž‹ (RESPONSE)
147   -00 // æ¶ˆæ¯æ ‡å¿— (预留)
148   -00 00 00 A5 // 消æ¯é•¿åº¦ (165字节)
  143 +00 00 00 A4 // 消æ¯é•¿åº¦ (164字节)
149 144 00 22 // æ¶ˆæ¯ ID 长度 (34字节)
150 145 61 75 74 68 5F 72 65 73 70 6F // æ¶ˆæ¯ ID: "auth_response_1704067200000_123"
151 146 6E 73 65 5F 31 37 30 34 30 36
... ... @@ -175,19 +170,19 @@ public static final String TYPE = &quot;TCP_BINARY&quot;;
175 170 - **æ•°æ®ç´§å‡‘**:二进制格å¼ï¼Œç›¸æ¯” JSON å‡å°‘ 30-50% 的数æ®é‡
176 171 - **è§£æžé«˜æ•ˆ**:直接二进制æ“作,å‡å°‘字符串转æ¢å¼€é”€
177 172 - **类型安全**:明确的消æ¯ç±»åž‹å’Œå­—段定义
178   -- **扩展性强**ï¼šé¢„ç•™æ ‡å¿—ä½æ”¯æŒæœªæ¥åŠŸèƒ½æ‰©å±•
  173 +- **设计简æ´**:去除冗余字段,å议更加精简高效
179 174 - **版本控制**ï¼šå†…ç½®ç‰ˆæœ¬å·æ”¯æŒåè®®å‡çº§
180 175  
181 176 ## 6. 与 JSON å议对比
182 177  
183   -| 特性 | 二进制åè®® | JSONåè®® |
184   -|------|------------|----------|
185   -| æ•°æ®å¤§å° | å°ï¼ˆèŠ‚çœ30-50%) | 大 |
186   -| è§£æžæ€§èƒ½ | 高 | 中等 |
187   -| 网络开销 | 低 | 高 |
188   -| å¯è¯»æ€§ | å·® | 优秀 |
189   -| 调试难度 | 高 | 低 |
190   -| 扩展性 | 良好(有预留ä½ï¼‰ | 优秀 |
  178 +| 特性 | 二进制åè®® | JSONåè®® |
  179 +|------|-------------|--------|
  180 +| æ•°æ®å¤§å° | å°ï¼ˆèŠ‚çœ30-50%) | 大 |
  181 +| è§£æžæ€§èƒ½ | 高 | 中等 |
  182 +| 网络开销 | 低 | 高 |
  183 +| å¯è¯»æ€§ | å·® | 优秀 |
  184 +| 调试难度 | 高 | 低 |
  185 +| 扩展性 | 良好 | 优秀 |
191 186  
192 187 **推è场景**:
193 188 - ✅ **高频数æ®ä¼ è¾“**:传感器数æ®å®žæ—¶ä¸ŠæŠ¥
... ...