Commit 0f9cf91899050d109105f8e5a8c53c39db35e6da

Authored by YunaiV
1 parent cda59081

review:【iot 物联网】tcp 协议的接入

yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/codec/tcp/IotTcpBinaryDeviceMessageCodec.java
... ... @@ -20,11 +20,11 @@ import java.nio.charset.StandardCharsets;
20 20 *
21 21 * <pre>
22 22 * +--------+--------+--------+--------+--------+--------+--------+--------+
23   - * | 魔术字 | 版本号 | 消息类型| 消息标志| 消息长度(4字节) |
  23 + * | 魔术字 | 版本号 | 消息类型| 消息标志| 消息长度(4 字节) |
24 24 * +--------+--------+--------+--------+--------+--------+--------+--------+
25   - * | 消息 ID 长度(2字节) | 消息 ID (变长字符串) |
  25 + * | 消息 ID 长度(2 字节) | 消息 ID (变长字符串) |
26 26 * +--------+--------+--------+--------+--------+--------+--------+--------+
27   - * | 方法名长度(2字节) | 方法名(变长字符串) |
  27 + * | 方法名长度(2 字节) | 方法名(变长字符串) |
28 28 * +--------+--------+--------+--------+--------+--------+--------+--------+
29 29 * | 消息体数据(变长) |
30 30 * +--------+--------+--------+--------+--------+--------+--------+--------+
... ... @@ -56,12 +56,21 @@ public class IotTcpBinaryDeviceMessageCodec implements IotDeviceMessageCodec {
56 56 */
57 57 private static final byte PROTOCOL_VERSION = (byte) 0x01;
58 58  
  59 + // TODO @haohao:这个要不直接静态枚举,不用 MessageType
59 60 /**
60 61 * 消息类型常量
61 62 */
62 63 public static class MessageType {
63   - public static final byte REQUEST = 0x01; // 请求消息
64   - public static final byte RESPONSE = 0x02; // 响应消息
  64 +
  65 + /**
  66 + * 请求消息
  67 + */
  68 + public static final byte REQUEST = 0x01;
  69 + /**
  70 + * 响应消息
  71 + */
  72 + public static final byte RESPONSE = 0x02;
  73 +
65 74 }
66 75  
67 76 /**
... ... @@ -83,17 +92,13 @@ public class IotTcpBinaryDeviceMessageCodec implements IotDeviceMessageCodec {
83 92 public byte[] encode(IotDeviceMessage message) {
84 93 Assert.notNull(message, "消息不能为空");
85 94 Assert.notBlank(message.getMethod(), "消息方法不能为空");
86   -
87 95 try {
88 96 // 1. 确定消息类型
89 97 byte messageType = determineMessageType(message);
90   -
91 98 // 2. 构建消息体
92 99 byte[] bodyData = buildMessageBody(message, messageType);
93   -
94 100 // 3. 构建完整消息(不包含deviceId,由连接上下文管理)
95 101 return buildCompleteMessage(message, messageType, bodyData);
96   -
97 102 } catch (Exception e) {
98 103 log.error("[encode][TCP 二进制消息编码失败,消息: {}]", message, e);
99 104 throw new RuntimeException("TCP 二进制消息编码失败: " + e.getMessage(), e);
... ... @@ -104,16 +109,12 @@ public class IotTcpBinaryDeviceMessageCodec implements IotDeviceMessageCodec {
104 109 public IotDeviceMessage decode(byte[] bytes) {
105 110 Assert.notNull(bytes, "待解码数据不能为空");
106 111 Assert.isTrue(bytes.length >= MIN_MESSAGE_LENGTH, "数据包长度不足");
107   -
108 112 try {
109 113 Buffer buffer = Buffer.buffer(bytes);
110   -
111 114 // 1. 解析协议头部
112 115 ProtocolHeader header = parseProtocolHeader(buffer);
113   -
114 116 // 2. 解析消息内容(不包含deviceId,由上层连接管理器设置)
115 117 return parseMessageContent(buffer, header);
116   -
117 118 } catch (Exception e) {
118 119 log.error("[decode][TCP 二进制消息解码失败,数据长度: {}]", bytes.length, e);
119 120 throw new RuntimeException("TCP 二进制消息解码失败: " + e.getMessage(), e);
... ... @@ -128,6 +129,7 @@ public class IotTcpBinaryDeviceMessageCodec implements IotDeviceMessageCodec {
128 129 */
129 130 private byte determineMessageType(IotDeviceMessage message) {
130 131 // 判断是否为响应消息:有响应码或响应消息时为响应
  132 + // TODO @haohao:感觉只判断 code 更稳妥点?msg 有可能空。。。
131 133 if (message.getCode() != null || StrUtil.isNotBlank(message.getMsg())) {
132 134 return MessageType.RESPONSE;
133 135 }
... ... @@ -140,27 +142,26 @@ public class IotTcpBinaryDeviceMessageCodec implements IotDeviceMessageCodec {
140 142 */
141 143 private byte[] buildMessageBody(IotDeviceMessage message, byte messageType) {
142 144 Buffer bodyBuffer = Buffer.buffer();
143   -
144 145 if (messageType == MessageType.RESPONSE) {
145   - // 响应消息:code + msg长度 + msg + data
  146 + // code
146 147 bodyBuffer.appendInt(message.getCode() != null ? message.getCode() : 0);
147   -
  148 + // msg
148 149 String msg = message.getMsg() != null ? message.getMsg() : "";
149 150 byte[] msgBytes = msg.getBytes(StandardCharsets.UTF_8);
150 151 bodyBuffer.appendShort((short) msgBytes.length);
151 152 bodyBuffer.appendBytes(msgBytes);
152   -
  153 + // data
153 154 if (message.getData() != null) {
154 155 bodyBuffer.appendBytes(JsonUtils.toJsonByte(message.getData()));
155 156 }
156 157 } else {
157   - // 请求消息:包含 params 或 data
  158 + // params
  159 + // TODO @haohao:请求是不是只处理 message.getParams() 哈?
158 160 Object payload = message.getParams() != null ? message.getParams() : message.getData();
159 161 if (payload != null) {
160 162 bodyBuffer.appendBytes(JsonUtils.toJsonByte(payload));
161 163 }
162 164 }
163   -
164 165 return bodyBuffer.getBytes();
165 166 }
166 167  
... ... @@ -169,35 +170,30 @@ public class IotTcpBinaryDeviceMessageCodec implements IotDeviceMessageCodec {
169 170 */
170 171 private byte[] buildCompleteMessage(IotDeviceMessage message, byte messageType, byte[] bodyData) {
171 172 Buffer buffer = Buffer.buffer();
172   -
173 173 // 1. 写入协议头部
174 174 buffer.appendByte(MAGIC_NUMBER);
175 175 buffer.appendByte(PROTOCOL_VERSION);
176 176 buffer.appendByte(messageType);
177   - buffer.appendByte((byte) 0x00); // 消息标志,预留字段
178   -
179   - // 2. 预留消息长度位置
  177 + buffer.appendByte((byte) 0x00); // 消息标志,预留字段 TODO @haohao:这个标识的作用是啥呀?
  178 + // 2. 预留消息长度位置(在 6. 更新消息长度)
180 179 int lengthPosition = buffer.length();
181 180 buffer.appendInt(0);
182   -
183   - // 3. 写入消息ID
  181 + // 3. 写入消息 ID
184 182 String messageId = StrUtil.isNotBlank(message.getRequestId()) ? message.getRequestId()
  183 + // TODO @haohao:复用 IotDeviceMessageUtils 的 generateMessageId 哇?
185 184 : generateMessageId(message.getMethod());
  185 + // TODO @haohao:StrUtil.utf8Bytes()
186 186 byte[] messageIdBytes = messageId.getBytes(StandardCharsets.UTF_8);
187 187 buffer.appendShort((short) messageIdBytes.length);
188 188 buffer.appendBytes(messageIdBytes);
189   -
190 189 // 4. 写入方法名
191 190 byte[] methodBytes = message.getMethod().getBytes(StandardCharsets.UTF_8);
192 191 buffer.appendShort((short) methodBytes.length);
193 192 buffer.appendBytes(methodBytes);
194   -
195 193 // 5. 写入消息体
196 194 buffer.appendBytes(bodyData);
197   -
198 195 // 6. 更新消息长度
199 196 buffer.setInt(lengthPosition, buffer.length());
200   -
201 197 return buffer.getBytes();
202 198 }
203 199  
... ... @@ -210,16 +206,15 @@ public class IotTcpBinaryDeviceMessageCodec implements IotDeviceMessageCodec {
210 206  
211 207 // ==================== 解码相关方法 ====================
212 208  
  209 + // TODO @haohao:是不是把 parseProtocolHeader、parseMessageContent 合并?
213 210 /**
214 211 * 解析协议头部
215 212 */
216 213 private ProtocolHeader parseProtocolHeader(Buffer buffer) {
217 214 int index = 0;
218   -
219 215 // 1. 验证魔术字
220 216 byte magic = buffer.getByte(index++);
221 217 Assert.isTrue(magic == MAGIC_NUMBER, "无效的协议魔术字: " + magic);
222   -
223 218 // 2. 验证版本号
224 219 byte version = buffer.getByte(index++);
225 220 Assert.isTrue(version == PROTOCOL_VERSION, "不支持的协议版本: " + version);
... ... @@ -227,7 +222,6 @@ public class IotTcpBinaryDeviceMessageCodec implements IotDeviceMessageCodec {
227 222 // 3. 读取消息类型
228 223 byte messageType = buffer.getByte(index++);
229 224 Assert.isTrue(isValidMessageType(messageType), "无效的消息类型: " + messageType);
230   -
231 225 // 4. 读取消息标志(暂时跳过)
232 226 byte messageFlags = buffer.getByte(index++);
233 227  
... ... @@ -235,7 +229,8 @@ public class IotTcpBinaryDeviceMessageCodec implements IotDeviceMessageCodec {
235 229 int messageLength = buffer.getInt(index);
236 230 index += 4;
237 231  
238   - Assert.isTrue(messageLength == buffer.length(), "消息长度不匹配,期望: " + messageLength + ", 实际: " + buffer.length());
  232 + Assert.isTrue(messageLength == buffer.length(),
  233 + "消息长度不匹配,期望: " + messageLength + ", 实际: " + buffer.length());
239 234  
240 235 return new ProtocolHeader(magic, version, messageType, messageFlags, messageLength, index);
241 236 }
... ... @@ -246,7 +241,7 @@ public class IotTcpBinaryDeviceMessageCodec implements IotDeviceMessageCodec {
246 241 private IotDeviceMessage parseMessageContent(Buffer buffer, ProtocolHeader header) {
247 242 int index = header.getNextIndex();
248 243  
249   - // 1. 读取消息ID
  244 + // 1. 读取消息 ID
250 245 short messageIdLength = buffer.getShort(index);
251 246 index += 2;
252 247 String messageId = buffer.getString(index, index + messageIdLength, StandardCharsets.UTF_8.name());
... ... @@ -314,12 +309,8 @@ public class IotTcpBinaryDeviceMessageCodec implements IotDeviceMessageCodec {
314 309 if (startIndex >= endIndex) {
315 310 return null;
316 311 }
317   -
318 312 try {
319 313 String jsonStr = buffer.getString(startIndex, endIndex, StandardCharsets.UTF_8.name());
320   - if (StrUtil.isBlank(jsonStr)) {
321   - return null;
322   - }
323 314 return JsonUtils.parseObject(jsonStr, Object.class);
324 315 } catch (Exception e) {
325 316 log.warn("[parseJsonData][JSON 解析失败,返回原始字符串]", e);
... ... @@ -329,6 +320,7 @@ public class IotTcpBinaryDeviceMessageCodec implements IotDeviceMessageCodec {
329 320  
330 321 // ==================== 辅助方法 ====================
331 322  
  323 + // TODO @haohao:这个貌似只用一次,可以考虑不抽小方法哈;
332 324 /**
333 325 * 验证消息类型是否有效
334 326 */
... ... @@ -344,11 +336,16 @@ public class IotTcpBinaryDeviceMessageCodec implements IotDeviceMessageCodec {
344 336 @Data
345 337 @AllArgsConstructor
346 338 private static class ProtocolHeader {
  339 +
347 340 private byte magic;
348 341 private byte version;
349 342 private byte messageType;
350 343 private byte messageFlags;
351 344 private int messageLength;
352   - private int nextIndex; // 指向消息内容开始位置
  345 + /**
  346 + * 指向消息内容开始位置
  347 + */
  348 + private int nextIndex;
  349 +
353 350 }
354 351 }
355 352 \ No newline at end of file
... ...
yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/codec/tcp/IotTcpJsonDeviceMessageCodec.java
... ... @@ -14,13 +14,13 @@ import org.springframework.stereotype.Component;
14 14 *
15 15 * 采用纯 JSON 格式传输,格式如下:
16 16 * {
17   - * "id": "消息 ID",
18   - * "method": "消息方法",
19   - * "params": {...}, // 请求参数
20   - * "data": {...}, // 响应结果
21   - * "code": 200, // 响应错误码
22   - * "msg": "success", // 响应提示
23   - * "timestamp": 时间戳
  17 + * "id": "消息 ID",
  18 + * "method": "消息方法",
  19 + * "params": {...}, // 请求参数
  20 + * "data": {...}, // 响应结果
  21 + * "code": 200, // 响应错误码
  22 + * "msg": "success", // 响应提示
  23 + * "timestamp": 时间戳
24 24 * }
25 25 *
26 26 * @author 芋道源码
... ...
yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/tcp/IotTcpUpstreamProtocol.java
... ... @@ -39,10 +39,10 @@ public class IotTcpUpstreamProtocol {
39 39 private NetServer tcpServer;
40 40  
41 41 public IotTcpUpstreamProtocol(IotGatewayProperties.TcpProperties tcpProperties,
42   - IotDeviceService deviceService,
43   - IotDeviceMessageService messageService,
  42 + IotDeviceService deviceService,
  43 + IotDeviceMessageService messageService,
44 44 IotTcpConnectionManager connectionManager,
45   - Vertx vertx) {
  45 + Vertx vertx) {
46 46 this.tcpProperties = tcpProperties;
47 47 this.deviceService = deviceService;
48 48 this.messageService = messageService;
... ...
yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/tcp/manager/IotTcpConnectionManager.java
... ... @@ -2,7 +2,6 @@ package cn.iocoder.yudao.module.iot.gateway.protocol.tcp.manager;
2 2  
3 3 import io.vertx.core.net.NetSocket;
4 4 import lombok.Data;
5   -import lombok.experimental.Accessors;
6 5 import lombok.extern.slf4j.Slf4j;
7 6 import org.springframework.stereotype.Component;
8 7  
... ... @@ -62,9 +61,9 @@ public class IotTcpConnectionManager {
62 61 .setDeviceId(deviceId)
63 62 .setAuthInfo(authInfo)
64 63 .setAuthenticated(true);
65   -
66 64 connectionMap.put(socket, connectionInfo);
67 65 deviceSocketMap.put(deviceId, socket);
  66 + // TODO @haohao:socketDeviceMap 和 connectionMap 会重复哇?connectionMap.get(socket).getDeviceId
68 67 socketDeviceMap.put(socket, deviceId);
69 68  
70 69 log.info("[registerConnection][注册设备连接,设备 ID: {},连接: {},product key: {},device name: {}]",
... ... @@ -79,7 +78,6 @@ public class IotTcpConnectionManager {
79 78 public void unregisterConnection(NetSocket socket) {
80 79 ConnectionInfo connectionInfo = connectionMap.remove(socket);
81 80 Long deviceId = socketDeviceMap.remove(socket);
82   -
83 81 if (connectionInfo != null && deviceId != null) {
84 82 deviceSocketMap.remove(deviceId);
85 83 log.info("[unregisterConnection][注销设备连接,设备 ID: {},连接: {}]",
... ... @@ -87,6 +85,7 @@ public class IotTcpConnectionManager {
87 85 }
88 86 }
89 87  
  88 + // TODO @haohao:用不到,要不暂时清理哈。
90 89 /**
91 90 * 注销设备连接(通过设备 ID)
92 91 *
... ... @@ -160,26 +159,30 @@ public class IotTcpConnectionManager {
160 159 }
161 160 }
162 161  
  162 + // TODO @haohao:ConnectionInfo 和 AuthInfo 是不是可以融合哈?
  163 +
163 164 /**
164 165 * 连接信息
165 166 */
166 167 @Data
167   - @Accessors(chain = true)
168 168 public static class ConnectionInfo {
  169 +
169 170 private Long deviceId;
170 171 private AuthInfo authInfo;
171 172 private boolean authenticated;
  173 +
172 174 }
173 175  
174 176 /**
175 177 * 认证信息
176 178 */
177 179 @Data
178   - @Accessors(chain = true)
179 180 public static class AuthInfo {
  181 +
180 182 private Long deviceId;
181 183 private String productKey;
182 184 private String deviceName;
183 185 private String clientId;
  186 +
184 187 }
185 188 }
186 189 \ 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/IotTcpDownstreamHandler.java
... ... @@ -47,7 +47,6 @@ public class IotTcpDownstreamHandler {
47 47 byte[] bytes = deviceMessageService.encodeDeviceMessage(message, deviceInfo.getProductKey(),
48 48 deviceInfo.getDeviceName());
49 49 boolean success = connectionManager.sendToDevice(message.getDeviceId(), bytes);
50   -
51 50 if (success) {
52 51 log.info("[handle][下行消息发送成功,设备 ID: {},方法: {},消息 ID: {},数据长度: {} 字节]",
53 52 message.getDeviceId(), message.getMethod(), message.getId(), bytes.length);
... ...
yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/tcp/router/IotTcpUpstreamHandler.java
... ... @@ -37,6 +37,7 @@ public class IotTcpUpstreamHandler implements Handler&lt;NetSocket&gt; {
37 37  
38 38 private static final String CODEC_TYPE_JSON = IotTcpJsonDeviceMessageCodec.TYPE;
39 39 private static final String CODEC_TYPE_BINARY = IotTcpBinaryDeviceMessageCodec.TYPE;
  40 +
40 41 private static final String AUTH_METHOD = "auth";
41 42  
42 43 private final IotDeviceMessageService deviceMessageService;
... ... @@ -49,8 +50,10 @@ public class IotTcpUpstreamHandler implements Handler&lt;NetSocket&gt; {
49 50  
50 51 private final String serverId;
51 52  
52   - public IotTcpUpstreamHandler(IotTcpUpstreamProtocol protocol, IotDeviceMessageService deviceMessageService,
53   - IotDeviceService deviceService, IotTcpConnectionManager connectionManager) {
  53 + public IotTcpUpstreamHandler(IotTcpUpstreamProtocol protocol,
  54 + IotDeviceMessageService deviceMessageService,
  55 + IotDeviceService deviceService,
  56 + IotTcpConnectionManager connectionManager) {
54 57 this.deviceMessageService = deviceMessageService;
55 58 this.deviceService = deviceService;
56 59 this.connectionManager = connectionManager;
... ... @@ -68,12 +71,12 @@ public class IotTcpUpstreamHandler implements Handler&lt;NetSocket&gt; {
68 71 log.warn("[handle][连接异常,客户端 ID: {},地址: {}]", clientId, socket.remoteAddress());
69 72 cleanupConnection(socket);
70 73 });
71   -
72 74 socket.closeHandler(v -> {
73 75 log.debug("[handle][连接关闭,客户端 ID: {},地址: {}]", clientId, socket.remoteAddress());
74 76 cleanupConnection(socket);
75 77 });
76 78  
  79 + // 设置消息处理器
77 80 socket.handler(buffer -> processMessage(clientId, buffer, socket));
78 81 }
79 82  
... ... @@ -82,26 +85,24 @@ public class IotTcpUpstreamHandler implements Handler&lt;NetSocket&gt; {
82 85 */
83 86 private void processMessage(String clientId, Buffer buffer, NetSocket socket) {
84 87 try {
85   - // 1. 数据包基础检查
  88 + // 1.1 数据包基础检查
86 89 if (buffer.length() == 0) {
87 90 return;
88 91 }
89   -
90   - // 2. 解码消息
  92 + // 1.2 解码消息
91 93 MessageInfo messageInfo = decodeMessage(buffer);
92 94 if (messageInfo == null) {
93 95 return;
94 96 }
95 97  
96   - // 3. 根据消息类型路由处理
  98 + // 2. 根据消息类型路由处理
97 99 if (isAuthRequest(messageInfo.message)) {
98   - // 认证请求:无需检查认证状态
  100 + // 认证请求
99 101 handleAuthenticationRequest(clientId, messageInfo, socket);
100 102 } else {
101   - // 业务消息:需要检查认证状态
  103 + // 业务消息
102 104 handleBusinessRequest(clientId, messageInfo, socket);
103 105 }
104   -
105 106 } catch (Exception e) {
106 107 log.error("[processMessage][处理消息失败,客户端 ID: {}]", clientId, e);
107 108 }
... ... @@ -112,16 +113,14 @@ public class IotTcpUpstreamHandler implements Handler&lt;NetSocket&gt; {
112 113 */
113 114 private void handleAuthenticationRequest(String clientId, MessageInfo messageInfo, NetSocket socket) {
114 115 try {
  116 + // 1.1 解析认证参数
115 117 IotDeviceMessage message = messageInfo.message;
116   -
117   - // 1. 解析认证参数
118 118 AuthParams authParams = parseAuthParams(message.getParams());
119 119 if (authParams == null) {
120 120 sendError(socket, message.getRequestId(), "认证参数不完整", messageInfo.codecType);
121 121 return;
122 122 }
123   -
124   - // 2. 执行认证
  123 + // 1.2 执行认证
125 124 if (!authenticateDevice(authParams)) {
126 125 log.warn("[handleAuthenticationRequest][认证失败,客户端 ID: {},username: {}]",
127 126 clientId, authParams.username);
... ... @@ -129,14 +128,13 @@ public class IotTcpUpstreamHandler implements Handler&lt;NetSocket&gt; {
129 128 return;
130 129 }
131 130  
132   - // 3. 解析设备信息
  131 + // 2.1 解析设备信息
133 132 IotDeviceAuthUtils.DeviceInfo deviceInfo = IotDeviceAuthUtils.parseUsername(authParams.username);
134 133 if (deviceInfo == null) {
135 134 sendError(socket, message.getRequestId(), "解析设备信息失败", messageInfo.codecType);
136 135 return;
137 136 }
138   -
139   - // 4. 获取设备信息
  137 + // 2.2 获取设备信息
140 138 IotDeviceRespDTO device = deviceService.getDeviceFromCache(deviceInfo.getProductKey(),
141 139 deviceInfo.getDeviceName());
142 140 if (device == null) {
... ... @@ -144,14 +142,12 @@ public class IotTcpUpstreamHandler implements Handler&lt;NetSocket&gt; {
144 142 return;
145 143 }
146 144  
147   - // 5. 注册连接并发送成功响应
  145 + // 3. 注册连接并发送成功响应
148 146 registerConnection(socket, device, deviceInfo, authParams.clientId);
149 147 sendOnlineMessage(deviceInfo);
150 148 sendSuccess(socket, message.getRequestId(), "认证成功", messageInfo.codecType);
151   -
152 149 log.info("[handleAuthenticationRequest][认证成功,设备 ID: {},设备名: {}]",
153 150 device.getId(), deviceInfo.getDeviceName());
154   -
155 151 } catch (Exception e) {
156 152 log.error("[handleAuthenticationRequest][认证处理异常,客户端 ID: {}]", clientId, e);
157 153 sendError(socket, messageInfo.message.getRequestId(), "认证处理异常", messageInfo.codecType);
... ... @@ -173,25 +169,23 @@ public class IotTcpUpstreamHandler implements Handler&lt;NetSocket&gt; {
173 169 // 2. 获取认证信息并处理业务消息
174 170 IotTcpConnectionManager.AuthInfo authInfo = connectionManager.getAuthInfo(socket);
175 171 processBusinessMessage(clientId, messageInfo.message, authInfo);
176   -
177 172 } catch (Exception e) {
178 173 log.error("[handleBusinessRequest][业务请求处理异常,客户端 ID: {}]", clientId, e);
179 174 }
180 175 }
181 176  
  177 + // TODO @haohao:processBusinessMessage 这个小方法,直接融合到 handleBusinessRequest 里?读起来更聚集点
182 178 /**
183 179 * 处理业务消息
184 180 */
185 181 private void processBusinessMessage(String clientId, IotDeviceMessage message,
186   - IotTcpConnectionManager.AuthInfo authInfo) {
  182 + IotTcpConnectionManager.AuthInfo authInfo) {
187 183 try {
188 184 message.setDeviceId(authInfo.getDeviceId());
189 185 message.setServerId(serverId);
190   -
191 186 // 发送到消息总线
192 187 deviceMessageService.sendDeviceMessage(message, authInfo.getProductKey(),
193 188 authInfo.getDeviceName(), serverId);
194   -
195 189 } catch (Exception e) {
196 190 log.error("[processBusinessMessage][业务消息处理失败,客户端 ID: {},消息 ID: {}]",
197 191 clientId, message.getId(), e);
... ... @@ -200,28 +194,27 @@ public class IotTcpUpstreamHandler implements Handler&lt;NetSocket&gt; {
200 194  
201 195 /**
202 196 * 解码消息
  197 + *
  198 + * @param buffer 消息
203 199 */
204 200 private MessageInfo decodeMessage(Buffer buffer) {
205 201 if (buffer == null || buffer.length() == 0) {
206 202 return null;
207 203 }
208   -
209 204 // 1. 快速检测消息格式类型
  205 + // TODO @haohao:是不是进一步优化?socket 建立认证后,那条消息已经定义了所有消息的格式哈?
210 206 String codecType = detectMessageFormat(buffer);
211   -
212 207 try {
213 208 // 2. 使用检测到的格式进行解码
214 209 IotDeviceMessage message = deviceMessageService.decodeDeviceMessage(buffer.getBytes(), codecType);
215   -
216 210 if (message == null) {
217 211 return null;
218 212 }
219   -
220 213 return new MessageInfo(message, codecType);
221   -
222 214 } catch (Exception e) {
223 215 log.warn("[decodeMessage][消息解码失败,格式: {},数据长度: {},错误: {}]",
224 216 codecType, buffer.length(), e.getMessage());
  217 + // TODO @haohao:一般消息格式不对,应该抛出异常,断开连接居多?
225 218 return null;
226 219 }
227 220 }
... ... @@ -231,8 +224,10 @@ public class IotTcpUpstreamHandler implements Handler&lt;NetSocket&gt; {
231 224 * 优化性能:避免不必要的字符串转换
232 225 */
233 226 private String detectMessageFormat(Buffer buffer) {
  227 + // TODO @haohao:是不是 IotTcpBinaryDeviceMessageCodec 提供一个 isBinaryFormat 方法哈?
  228 + // 默认使用 JSON
234 229 if (buffer.length() == 0) {
235   - return CODEC_TYPE_JSON; // 默认使用 JSON
  230 + return CODEC_TYPE_JSON;
236 231 }
237 232  
238 233 // 1. 优先检测二进制格式(检查魔术字节 0x7E)
... ... @@ -241,6 +236,7 @@ public class IotTcpUpstreamHandler implements Handler&lt;NetSocket&gt; {
241 236 }
242 237  
243 238 // 2. 检测 JSON 格式(检查前几个有效字符)
  239 + // TODO @haohao:这个检测去掉?直接 return CODEC_TYPE_JSON 更简洁一点。
244 240 if (isJsonFormat(buffer)) {
245 241 return CODEC_TYPE_JSON;
246 242 }
... ... @@ -295,14 +291,14 @@ public class IotTcpUpstreamHandler implements Handler&lt;NetSocket&gt; {
295 291 * 注册连接信息
296 292 */
297 293 private void registerConnection(NetSocket socket, IotDeviceRespDTO device,
298   - IotDeviceAuthUtils.DeviceInfo deviceInfo, String clientId) {
  294 + IotDeviceAuthUtils.DeviceInfo deviceInfo, String clientId) {
  295 + // TODO @haohao:AuthInfo 的创建,放在 connectionManager 里构建貌似会更收敛一点?
299 296 // 创建认证信息
300 297 IotTcpConnectionManager.AuthInfo authInfo = new IotTcpConnectionManager.AuthInfo()
301 298 .setDeviceId(device.getId())
302 299 .setProductKey(deviceInfo.getProductKey())
303 300 .setDeviceName(deviceInfo.getDeviceName())
304 301 .setClientId(clientId);
305   -
306 302 // 注册连接
307 303 connectionManager.registerConnection(socket, device.getId(), authInfo);
308 304 }
... ... @@ -377,15 +373,12 @@ public class IotTcpUpstreamHandler implements Handler&lt;NetSocket&gt; {
377 373 if (params == null) {
378 374 return null;
379 375 }
380   -
381 376 try {
382 377 JSONObject paramsJson = params instanceof JSONObject ? (JSONObject) params
383 378 : JSONUtil.parseObj(params.toString());
384   -
385 379 String clientId = paramsJson.getStr("clientId");
386 380 String username = paramsJson.getStr("username");
387 381 String password = paramsJson.getStr("password");
388   -
389 382 return StrUtil.hasBlank(clientId, username, password) ? null
390 383 : new AuthParams(clientId, username, password);
391 384 } catch (Exception e) {
... ... @@ -410,6 +403,8 @@ public class IotTcpUpstreamHandler implements Handler&lt;NetSocket&gt; {
410 403 }
411 404 }
412 405  
  406 + // TODO @haohao:改成 sendErrorResponse sendSuccessResponse 更清晰点?
  407 +
413 408 /**
414 409 * 发送错误响应
415 410 */
... ... @@ -426,15 +421,18 @@ public class IotTcpUpstreamHandler implements Handler&lt;NetSocket&gt; {
426 421  
427 422 // ==================== 内部类 ====================
428 423  
  424 + // TODO @haohao:IotDeviceAuthReqDTO 复用这个?
429 425 /**
430 426 * 认证参数
431 427 */
432 428 @Data
433 429 @AllArgsConstructor
434 430 private static class AuthParams {
  431 +
435 432 private final String clientId;
436 433 private final String username;
437 434 private final String password;
  435 +
438 436 }
439 437  
440 438 /**
... ... @@ -443,7 +441,10 @@ public class IotTcpUpstreamHandler implements Handler&lt;NetSocket&gt; {
443 441 @Data
444 442 @AllArgsConstructor
445 443 private static class MessageInfo {
  444 +
446 445 private final IotDeviceMessage message;
  446 +
447 447 private final String codecType;
  448 +
448 449 }
449 450 }
450 451 \ No newline at end of file
... ...