Commit 6a117c9d550ac8bc9448d0eac23b8512dbccf515

Authored by YunaiV
1 parent bb1210a1

review:【IoT 物联网】TCP 网络接入的实现

Showing 11 changed files with 114 additions and 121 deletions
yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/codec/tcp/IotTcpDeviceMessageCodec.java
@@ -54,6 +54,7 @@ public class IotTcpDeviceMessageCodec implements IotDeviceMessageCodec { @@ -54,6 +54,7 @@ public class IotTcpDeviceMessageCodec implements IotDeviceMessageCodec {
54 54
55 static { 55 static {
56 // 初始化方法映射 56 // 初始化方法映射
  57 + // TODO @haohao:有没可能去掉这个 code 到 method 的映射哈?
57 initializeMethodMappings(); 58 initializeMethodMappings();
58 } 59 }
59 60
@@ -75,6 +76,7 @@ public class IotTcpDeviceMessageCodec implements IotDeviceMessageCodec { @@ -75,6 +76,7 @@ public class IotTcpDeviceMessageCodec implements IotDeviceMessageCodec {
75 * 负载字段名 76 * 负载字段名
76 */ 77 */
77 public static class PayloadField { 78 public static class PayloadField {
  79 +
78 public static final String TIMESTAMP = "timestamp"; 80 public static final String TIMESTAMP = "timestamp";
79 public static final String MESSAGE_ID = "msgId"; 81 public static final String MESSAGE_ID = "msgId";
80 public static final String DEVICE_ID = "deviceId"; 82 public static final String DEVICE_ID = "deviceId";
@@ -82,12 +84,14 @@ public class IotTcpDeviceMessageCodec implements IotDeviceMessageCodec { @@ -82,12 +84,14 @@ public class IotTcpDeviceMessageCodec implements IotDeviceMessageCodec {
82 public static final String DATA = "data"; 84 public static final String DATA = "data";
83 public static final String CODE = "code"; 85 public static final String CODE = "code";
84 public static final String MESSAGE = "message"; 86 public static final String MESSAGE = "message";
  87 +
85 } 88 }
86 89
87 /** 90 /**
88 * 消息方法映射 91 * 消息方法映射
89 */ 92 */
90 public static class MessageMethod { 93 public static class MessageMethod {
  94 +
91 public static final String PROPERTY_POST = "thing.property.post"; 95 public static final String PROPERTY_POST = "thing.property.post";
92 public static final String PROPERTY_SET = "thing.property.set"; 96 public static final String PROPERTY_SET = "thing.property.set";
93 public static final String PROPERTY_GET = "thing.property.get"; 97 public static final String PROPERTY_GET = "thing.property.get";
@@ -97,6 +101,7 @@ public class IotTcpDeviceMessageCodec implements IotDeviceMessageCodec { @@ -97,6 +101,7 @@ public class IotTcpDeviceMessageCodec implements IotDeviceMessageCodec {
97 public static final String OTA_UPGRADE = "thing.ota.upgrade"; 101 public static final String OTA_UPGRADE = "thing.ota.upgrade";
98 public static final String STATE_ONLINE = "thing.state.online"; 102 public static final String STATE_ONLINE = "thing.state.online";
99 public static final String STATE_OFFLINE = "thing.state.offline"; 103 public static final String STATE_OFFLINE = "thing.state.offline";
  104 +
100 } 105 }
101 106
102 // ==================== 初始化方法 ==================== 107 // ==================== 初始化方法 ====================
@@ -139,9 +144,9 @@ public class IotTcpDeviceMessageCodec implements IotDeviceMessageCodec { @@ -139,9 +144,9 @@ public class IotTcpDeviceMessageCodec implements IotDeviceMessageCodec {
139 144
140 // 3. 构建 TCP 数据包 145 // 3. 构建 TCP 数据包
141 TcpDataPackage dataPackage = TcpDataPackage.builder() 146 TcpDataPackage dataPackage = TcpDataPackage.builder()
142 - .addr("") // 地址在发送时由调用方设置 147 + .addr("")
143 .code(code) 148 .code(code)
144 - .mid((short) 0) // 消息序号在发送时由调用方设置 149 + .mid((short) 0)
145 .payload(payload) 150 .payload(payload)
146 .build(); 151 .build();
147 152
@@ -154,9 +159,7 @@ public class IotTcpDeviceMessageCodec implements IotDeviceMessageCodec { @@ -154,9 +159,7 @@ public class IotTcpDeviceMessageCodec implements IotDeviceMessageCodec {
154 log.debug("[encode][TCP 消息编码成功] 方法: {}, 数据长度: {}", 159 log.debug("[encode][TCP 消息编码成功] 方法: {}, 数据长度: {}",
155 message.getMethod(), result.length); 160 message.getMethod(), result.length);
156 } 161 }
157 -  
158 return result; 162 return result;
159 -  
160 } catch (Exception e) { 163 } catch (Exception e) {
161 log.error("[encode][TCP 消息编码失败] 消息: {}", message, e); 164 log.error("[encode][TCP 消息编码失败] 消息: {}", message, e);
162 throw new TcpCodecException("TCP 消息编码失败", e); 165 throw new TcpCodecException("TCP 消息编码失败", e);
@@ -175,13 +178,10 @@ public class IotTcpDeviceMessageCodec implements IotDeviceMessageCodec { @@ -175,13 +178,10 @@ public class IotTcpDeviceMessageCodec implements IotDeviceMessageCodec {
175 // 1. 解码 TCP 数据包 178 // 1. 解码 TCP 数据包
176 Buffer buffer = Buffer.buffer(bytes); 179 Buffer buffer = Buffer.buffer(bytes);
177 TcpDataPackage dataPackage = TcpDataDecoder.decode(buffer); 180 TcpDataPackage dataPackage = TcpDataDecoder.decode(buffer);
178 -  
179 // 2. 获取消息方法 181 // 2. 获取消息方法
180 String method = getMethodByCodeSafely(dataPackage.getCode()); 182 String method = getMethodByCodeSafely(dataPackage.getCode());
181 -  
182 // 3. 解析负载数据 183 // 3. 解析负载数据
183 Object params = parsePayloadOptimized(dataPackage.getPayload()); 184 Object params = parsePayloadOptimized(dataPackage.getPayload());
184 -  
185 // 4. 构建 IoT 设备消息 185 // 4. 构建 IoT 设备消息
186 IotDeviceMessage message = IotDeviceMessage.requestOf(method, params); 186 IotDeviceMessage message = IotDeviceMessage.requestOf(method, params);
187 187
@@ -190,9 +190,7 @@ public class IotTcpDeviceMessageCodec implements IotDeviceMessageCodec { @@ -190,9 +190,7 @@ public class IotTcpDeviceMessageCodec implements IotDeviceMessageCodec {
190 log.debug("[decode][TCP 消息解码成功] 方法: {}, 功能码: {}", 190 log.debug("[decode][TCP 消息解码成功] 方法: {}, 功能码: {}",
191 method, dataPackage.getCode()); 191 method, dataPackage.getCode());
192 } 192 }
193 -  
194 return message; 193 return message;
195 -  
196 } catch (Exception e) { 194 } catch (Exception e) {
197 log.error("[decode][TCP 消息解码失败] 数据长度: {}, 数据内容: {}", 195 log.error("[decode][TCP 消息解码失败] 数据长度: {}, 数据内容: {}",
198 bytes.length, truncateData(bytes, 100), e); 196 bytes.length, truncateData(bytes, 100), e);
@@ -226,8 +224,8 @@ public class IotTcpDeviceMessageCodec implements IotDeviceMessageCodec { @@ -226,8 +224,8 @@ public class IotTcpDeviceMessageCodec implements IotDeviceMessageCodec {
226 if (Objects.isNull(bytes) || bytes.length == 0) { 224 if (Objects.isNull(bytes) || bytes.length == 0) {
227 throw new IllegalArgumentException("待解码数据不能为空"); 225 throw new IllegalArgumentException("待解码数据不能为空");
228 } 226 }
229 - if (bytes.length > 1024 * 1024) { // 1MB 限制  
230 - throw new IllegalArgumentException("数据包过大,超过1MB限制"); 227 + if (bytes.length > 1024 * 1024) {
  228 + throw new IllegalArgumentException("数据包过大,超过 1MB 限制");
231 } 229 }
232 } 230 }
233 231
@@ -236,9 +234,10 @@ public class IotTcpDeviceMessageCodec implements IotDeviceMessageCodec { @@ -236,9 +234,10 @@ public class IotTcpDeviceMessageCodec implements IotDeviceMessageCodec {
236 */ 234 */
237 private short getCodeByMethodSafely(String method) { 235 private short getCodeByMethodSafely(String method) {
238 Short code = METHOD_TO_CODE_MAP.get(method); 236 Short code = METHOD_TO_CODE_MAP.get(method);
  237 + // 默认为数据上报
239 if (code == null) { 238 if (code == null) {
240 log.warn("[getCodeByMethodSafely][未知的消息方法: {},使用默认功能码]", method); 239 log.warn("[getCodeByMethodSafely][未知的消息方法: {},使用默认功能码]", method);
241 - return TcpDataPackage.CODE_DATA_UP; // 默认为数据上报 240 + return TcpDataPackage.CODE_DATA_UP;
242 } 241 }
243 return code; 242 return code;
244 } 243 }
@@ -260,6 +259,7 @@ public class IotTcpDeviceMessageCodec implements IotDeviceMessageCodec { @@ -260,6 +259,7 @@ public class IotTcpDeviceMessageCodec implements IotDeviceMessageCodec {
260 */ 259 */
261 private String buildPayloadOptimized(IotDeviceMessage message) { 260 private String buildPayloadOptimized(IotDeviceMessage message) {
262 // 使用缓存键 261 // 使用缓存键
  262 + // TODO @haohao:是不是不用缓存哈?
263 String cacheKey = message.getMethod() + "_" + message.getRequestId(); 263 String cacheKey = message.getMethod() + "_" + message.getRequestId();
264 JSONObject cachedPayload = jsonCache.get(cacheKey); 264 JSONObject cachedPayload = jsonCache.get(cacheKey);
265 265
@@ -271,7 +271,6 @@ public class IotTcpDeviceMessageCodec implements IotDeviceMessageCodec { @@ -271,7 +271,6 @@ public class IotTcpDeviceMessageCodec implements IotDeviceMessageCodec {
271 271
272 // 创建新的负载 272 // 创建新的负载
273 JSONObject payload = new JSONObject(); 273 JSONObject payload = new JSONObject();
274 -  
275 // 添加基础字段 274 // 添加基础字段
276 addToPayloadIfNotNull(payload, PayloadField.MESSAGE_ID, message.getRequestId()); 275 addToPayloadIfNotNull(payload, PayloadField.MESSAGE_ID, message.getRequestId());
277 addToPayloadIfNotNull(payload, PayloadField.DEVICE_ID, message.getDeviceId()); 276 addToPayloadIfNotNull(payload, PayloadField.DEVICE_ID, message.getDeviceId());
@@ -279,7 +278,6 @@ public class IotTcpDeviceMessageCodec implements IotDeviceMessageCodec { @@ -279,7 +278,6 @@ public class IotTcpDeviceMessageCodec implements IotDeviceMessageCodec {
279 addToPayloadIfNotNull(payload, PayloadField.DATA, message.getData()); 278 addToPayloadIfNotNull(payload, PayloadField.DATA, message.getData());
280 addToPayloadIfNotNull(payload, PayloadField.CODE, message.getCode()); 279 addToPayloadIfNotNull(payload, PayloadField.CODE, message.getCode());
281 addToPayloadIfNotEmpty(payload, PayloadField.MESSAGE, message.getMsg()); 280 addToPayloadIfNotEmpty(payload, PayloadField.MESSAGE, message.getMsg());
282 -  
283 // 添加时间戳 281 // 添加时间戳
284 payload.set(PayloadField.TIMESTAMP, System.currentTimeMillis()); 282 payload.set(PayloadField.TIMESTAMP, System.currentTimeMillis());
285 283
@@ -317,7 +315,6 @@ public class IotTcpDeviceMessageCodec implements IotDeviceMessageCodec { @@ -317,7 +315,6 @@ public class IotTcpDeviceMessageCodec implements IotDeviceMessageCodec {
317 } 315 }
318 316
319 return jsonObject.containsKey(PayloadField.PARAMS) ? jsonObject.get(PayloadField.PARAMS) : jsonObject; 317 return jsonObject.containsKey(PayloadField.PARAMS) ? jsonObject.get(PayloadField.PARAMS) : jsonObject;
320 -  
321 } catch (JSONException e) { 318 } catch (JSONException e) {
322 log.warn("[parsePayloadOptimized][负载解析为JSON失败,返回原始字符串] 负载: {}", payload); 319 log.warn("[parsePayloadOptimized][负载解析为JSON失败,返回原始字符串] 负载: {}", payload);
323 return payload; 320 return payload;
@@ -379,6 +376,7 @@ public class IotTcpDeviceMessageCodec implements IotDeviceMessageCodec { @@ -379,6 +376,7 @@ public class IotTcpDeviceMessageCodec implements IotDeviceMessageCodec {
379 * TCP 编解码异常 376 * TCP 编解码异常
380 */ 377 */
381 public static class TcpCodecException extends RuntimeException { 378 public static class TcpCodecException extends RuntimeException {
  379 +
382 public TcpCodecException(String message) { 380 public TcpCodecException(String message) {
383 super(message); 381 super(message);
384 } 382 }
@@ -386,5 +384,6 @@ public class IotTcpDeviceMessageCodec implements IotDeviceMessageCodec { @@ -386,5 +384,6 @@ public class IotTcpDeviceMessageCodec implements IotDeviceMessageCodec {
386 public TcpCodecException(String message, Throwable cause) { 384 public TcpCodecException(String message, Throwable cause) {
387 super(message, cause); 385 super(message, cause);
388 } 386 }
  387 +
389 } 388 }
390 } 389 }
391 \ No newline at end of file 390 \ No newline at end of file
yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/tcp/IotTcpDownstreamSubscriber.java
@@ -108,16 +108,14 @@ public class IotTcpDownstreamSubscriber implements IotMessageSubscriber<IotDevic @@ -108,16 +108,14 @@ public class IotTcpDownstreamSubscriber implements IotMessageSubscriber<IotDevic
108 processedMessages.incrementAndGet(); 108 processedMessages.incrementAndGet();
109 109
110 if (log.isDebugEnabled()) { 110 if (log.isDebugEnabled()) {
111 - log.debug("[onMessage][收到下行消息] 设备ID: {}, 方法: {}, 消息ID: {}", 111 + log.debug("[onMessage][收到下行消息] 设备 ID: {}, 方法: {}, 消息ID: {}",
112 message.getDeviceId(), message.getMethod(), message.getId()); 112 message.getDeviceId(), message.getMethod(), message.getId());
113 } 113 }
114 -  
115 // 参数校验 114 // 参数校验
116 if (message.getDeviceId() == null) { 115 if (message.getDeviceId() == null) {
117 - log.warn("[onMessage][下行消息设备ID为空,跳过处理] 消息: {}", message); 116 + log.warn("[onMessage][下行消息设备 ID 为空,跳过处理] 消息: {}", message);
118 return; 117 return;
119 } 118 }
120 -  
121 // 检查连接状态 119 // 检查连接状态
122 if (connectionManager.getClientByDeviceId(message.getDeviceId()) == null) { 120 if (connectionManager.getClientByDeviceId(message.getDeviceId()) == null) {
123 log.warn("[onMessage][设备({})离线,跳过下行消息] 方法: {}", 121 log.warn("[onMessage][设备({})离线,跳过下行消息] 方法: {}",
@@ -130,11 +128,11 @@ public class IotTcpDownstreamSubscriber implements IotMessageSubscriber<IotDevic @@ -130,11 +128,11 @@ public class IotTcpDownstreamSubscriber implements IotMessageSubscriber<IotDevic
130 128
131 // 性能监控 129 // 性能监控
132 long processTime = System.currentTimeMillis() - startTime; 130 long processTime = System.currentTimeMillis() - startTime;
133 - if (processTime > 1000) { // 超过1秒的慢消息 131 + // TODO @haohao:1000 搞成静态变量;
  132 + if (processTime > 1000) { // 超过 1 秒的慢消息
134 log.warn("[onMessage][慢消息处理] 设备ID: {}, 方法: {}, 耗时: {}ms", 133 log.warn("[onMessage][慢消息处理] 设备ID: {}, 方法: {}, 耗时: {}ms",
135 message.getDeviceId(), message.getMethod(), processTime); 134 message.getDeviceId(), message.getMethod(), processTime);
136 } 135 }
137 -  
138 } catch (Exception e) { 136 } catch (Exception e) {
139 failedMessages.incrementAndGet(); 137 failedMessages.incrementAndGet();
140 log.error("[onMessage][处理下行消息失败] 设备ID: {}, 方法: {}, 消息: {}", 138 log.error("[onMessage][处理下行消息失败] 设备ID: {}, 方法: {}, 消息: {}",
@@ -142,6 +140,8 @@ public class IotTcpDownstreamSubscriber implements IotMessageSubscriber<IotDevic @@ -142,6 +140,8 @@ public class IotTcpDownstreamSubscriber implements IotMessageSubscriber<IotDevic
142 } 140 }
143 } 141 }
144 142
  143 + // TODO @haohao:多余的要不先清理掉;
  144 +
145 /** 145 /**
146 * 获取订阅者统计信息 146 * 获取订阅者统计信息
147 */ 147 */
@@ -160,4 +160,5 @@ public class IotTcpDownstreamSubscriber implements IotMessageSubscriber<IotDevic @@ -160,4 +160,5 @@ public class IotTcpDownstreamSubscriber implements IotMessageSubscriber<IotDevic
160 public boolean isHealthy() { 160 public boolean isHealthy() {
161 return initialized.get() && downstreamHandler != null; 161 return initialized.get() && downstreamHandler != null;
162 } 162 }
  163 +
163 } 164 }
164 \ No newline at end of file 165 \ No newline at end of file
yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/tcp/IotTcpUpstreamProtocol.java
@@ -92,6 +92,7 @@ public class IotTcpUpstreamProtocol { @@ -92,6 +92,7 @@ public class IotTcpUpstreamProtocol {
92 * 启动 TCP 服务器 92 * 启动 TCP 服务器
93 */ 93 */
94 private void startTcpServer() { 94 private void startTcpServer() {
  95 + // TODO @haohao:同类的,最好使用相同序号前缀,一个方法看起来有段落感。包括同类可以去掉之间的空格。例如说这里的,1. 2. 3. 4. 是初始化;5. 6. 是管理启动
95 // 1. 创建服务器选项 96 // 1. 创建服务器选项
96 NetServerOptions options = new NetServerOptions() 97 NetServerOptions options = new NetServerOptions()
97 .setPort(tcpProperties.getPort()) 98 .setPort(tcpProperties.getPort())
yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/tcp/client/TcpDeviceClient.java
@@ -10,9 +10,8 @@ import lombok.extern.slf4j.Slf4j; @@ -10,9 +10,8 @@ import lombok.extern.slf4j.Slf4j;
10 import java.util.concurrent.atomic.AtomicBoolean; 10 import java.util.concurrent.atomic.AtomicBoolean;
11 11
12 /** 12 /**
13 - * TCP 设备客户端 13 + * TCP 设备客户端:封装设备连接的基本信息和操作
14 * <p> 14 * <p>
15 - * 封装设备连接的基本信息和操作。  
16 * 该类中的状态变更(如 authenticated, closed)使用 AtomicBoolean 保证原子性。 15 * 该类中的状态变更(如 authenticated, closed)使用 AtomicBoolean 保证原子性。
17 * 对 socket 的操作应在 Vert.x Event Loop 线程中执行,以避免并发问题。 16 * 对 socket 的操作应在 Vert.x Event Loop 线程中执行,以避免并发问题。
18 * 17 *
@@ -48,7 +47,7 @@ public class TcpDeviceClient { @@ -48,7 +47,7 @@ public class TcpDeviceClient {
48 private RecordParser parser; 47 private RecordParser parser;
49 48
50 @Getter 49 @Getter
51 - private final long keepAliveTimeoutMs; // 改为 final,通过构造函数注入 50 + private final long keepAliveTimeoutMs;
52 51
53 private volatile long lastKeepAliveTime; 52 private volatile long lastKeepAliveTime;
54 53
@@ -58,7 +57,7 @@ public class TcpDeviceClient { @@ -58,7 +57,7 @@ public class TcpDeviceClient {
58 /** 57 /**
59 * 构造函数 58 * 构造函数
60 * 59 *
61 - * @param clientId 客户端ID,全局唯一 60 + * @param clientId 客户端 ID,全局唯一
62 * @param keepAliveTimeoutMs 心跳超时时间(毫秒),从配置中读取 61 * @param keepAliveTimeoutMs 心跳超时时间(毫秒),从配置中读取
63 */ 62 */
64 public TcpDeviceClient(String clientId, long keepAliveTimeoutMs) { 63 public TcpDeviceClient(String clientId, long keepAliveTimeoutMs) {
@@ -69,19 +68,19 @@ public class TcpDeviceClient { @@ -69,19 +68,19 @@ public class TcpDeviceClient {
69 68
70 /** 69 /**
71 * 绑定网络套接字,并设置相关处理器。 70 * 绑定网络套接字,并设置相关处理器。
72 - * 此方法应在 Vert.x Event Loop 线程中调用。 71 + * 此方法应在 Vert.x Event Loop 线程中调用
73 * 72 *
74 * @param socket 网络套接字 73 * @param socket 网络套接字
75 */ 74 */
76 public void setSocket(NetSocket socket) { 75 public void setSocket(NetSocket socket) {
77 // 无需 synchronized,Vert.x 保证了同一个 socket 的事件在同一个 Event Loop 中处理 76 // 无需 synchronized,Vert.x 保证了同一个 socket 的事件在同一个 Event Loop 中处理
78 if (this.socket != null && this.socket != socket) { 77 if (this.socket != null && this.socket != socket) {
79 - log.warn("[setSocket][客户端({})] 正在用新的 socket 替换旧的,旧 socket 将被关闭。", clientId); 78 + log.warn("[setSocket][客户端({}) 正在用新的 socket 替换旧的,旧 socket 将被关闭]", clientId);
80 this.socket.close(); 79 this.socket.close();
81 } 80 }
82 -  
83 this.socket = socket; 81 this.socket = socket;
84 82
  83 + // 注册处理器
85 if (socket != null) { 84 if (socket != null) {
86 // 1. 设置关闭处理器 85 // 1. 设置关闭处理器
87 socket.closeHandler(v -> { 86 socket.closeHandler(v -> {
@@ -103,22 +102,22 @@ public class TcpDeviceClient { @@ -103,22 +102,22 @@ public class TcpDeviceClient {
103 if (parser != null) { 102 if (parser != null) {
104 parser.handle(buffer); 103 parser.handle(buffer);
105 } else { 104 } else {
106 - log.warn("[setSocket][设备客户端({})] 未设置解析器(parser),原始数据被忽略: {}", clientId, buffer.toString()); 105 + log.warn("[setSocket][设备客户端({}) 未设置解析器(parser),原始数据被忽略: {}]", clientId, buffer.toString());
107 } 106 }
108 }); 107 });
109 } 108 }
110 } 109 }
111 110
112 /** 111 /**
113 - * 更新心跳时间,表示设备仍然活跃。 112 + * 更新心跳时间,表示设备仍然活跃
114 */ 113 */
115 public void keepAlive() { 114 public void keepAlive() {
116 this.lastKeepAliveTime = System.currentTimeMillis(); 115 this.lastKeepAliveTime = System.currentTimeMillis();
117 } 116 }
118 117
119 /** 118 /**
120 - * 检查连接是否在线。  
121 - * 判断标准:未被主动关闭、socket 存在、且在心跳超时时间内。 119 + * 检查连接是否在线
  120 + * 判断标准:未被主动关闭、socket 存在、且在心跳超时时间内
122 * 121 *
123 * @return 是否在线 122 * @return 是否在线
124 */ 123 */
@@ -130,6 +129,8 @@ public class TcpDeviceClient { @@ -130,6 +129,8 @@ public class TcpDeviceClient {
130 return idleTime < keepAliveTimeoutMs; 129 return idleTime < keepAliveTimeoutMs;
131 } 130 }
132 131
  132 + // TODO @haohao:1)是不是简化下:productKey 和 deviceName 非空,就认为是已认证;2)如果是的话,productKey 和 deviceName 搞成一个设置方法?setAuthenticated(productKey、deviceName)
  133 +
133 public boolean isAuthenticated() { 134 public boolean isAuthenticated() {
134 return authenticated.get(); 135 return authenticated.get();
135 } 136 }
@@ -139,7 +140,7 @@ public class TcpDeviceClient { @@ -139,7 +140,7 @@ public class TcpDeviceClient {
139 } 140 }
140 141
141 /** 142 /**
142 - * 向设备发送消息。 143 + * 向设备发送消息
143 * 144 *
144 * @param buffer 消息内容 145 * @param buffer 消息内容
145 */ 146 */
@@ -151,18 +152,22 @@ public class TcpDeviceClient { @@ -151,18 +152,22 @@ public class TcpDeviceClient {
151 152
152 // Vert.x 的 write 是异步的,不会阻塞 153 // Vert.x 的 write 是异步的,不会阻塞
153 socket.write(buffer, result -> { 154 socket.write(buffer, result -> {
154 - if (result.succeeded()) {  
155 - log.debug("[sendMessage][设备客户端({})发送消息成功]", clientId);  
156 - // 发送成功也更新心跳,表示连接活跃  
157 - keepAlive();  
158 - } else { 155 + // 发送失败可能意味着连接已断开,主动关闭
  156 + if (!result.succeeded()) {
159 log.error("[sendMessage][设备客户端({})发送消息失败]", clientId, result.cause()); 157 log.error("[sendMessage][设备客户端({})发送消息失败]", clientId, result.cause());
160 - // 发送失败可能意味着连接已断开,主动关闭  
161 shutdown(); 158 shutdown();
  159 + return;
  160 + }
  161 +
  162 + // 发送成功也更新心跳,表示连接活跃
  163 + if (log.isDebugEnabled()) {
  164 + log.debug("[sendMessage][设备客户端({})发送消息成功]", clientId);
162 } 165 }
  166 + keepAlive();
163 }); 167 });
164 } 168 }
165 169
  170 + // TODO @haohao:是不是叫 close 好点?或者问问大模型
166 /** 171 /**
167 * 关闭客户端连接并清理资源。 172 * 关闭客户端连接并清理资源。
168 * 这是一个幂等操作,可以被多次安全调用。 173 * 这是一个幂等操作,可以被多次安全调用。
@@ -200,10 +205,6 @@ public class TcpDeviceClient { @@ -200,10 +205,6 @@ public class TcpDeviceClient {
200 return "disconnected"; 205 return "disconnected";
201 } 206 }
202 207
203 - public long getLastKeepAliveTime() {  
204 - return lastKeepAliveTime;  
205 - }  
206 -  
207 @Override 208 @Override
208 public String toString() { 209 public String toString() {
209 return "TcpDeviceClient{" + 210 return "TcpDeviceClient{" +
@@ -215,4 +216,5 @@ public class TcpDeviceClient { @@ -215,4 +216,5 @@ public class TcpDeviceClient {
215 ", connection=" + getConnectionInfo() + 216 ", connection=" + getConnectionInfo() +
216 '}'; 217 '}';
217 } 218 }
  219 +
218 } 220 }
219 \ No newline at end of file 221 \ 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/TcpDeviceConnectionManager.java
@@ -16,8 +16,8 @@ import java.util.concurrent.locks.ReentrantReadWriteLock; @@ -16,8 +16,8 @@ import java.util.concurrent.locks.ReentrantReadWriteLock;
16 * 参考 EMQX 设计理念: 16 * 参考 EMQX 设计理念:
17 * 1. 高性能连接管理 17 * 1. 高性能连接管理
18 * 2. 连接池和资源管理 18 * 2. 连接池和资源管理
19 - * 3. 流量控制  
20 - * 4. 监控统计 19 + * 3. 流量控制 TODO @haohao:这个要不先去掉
  20 + * 4. 监控统计 TODO @haohao:这个要不先去掉
21 * 5. 自动清理和容错 21 * 5. 自动清理和容错
22 * 22 *
23 * @author 芋道源码 23 * @author 芋道源码
@@ -106,6 +106,7 @@ public class TcpDeviceConnectionManager { @@ -106,6 +106,7 @@ public class TcpDeviceConnectionManager {
106 * 添加设备客户端 106 * 添加设备客户端
107 */ 107 */
108 public boolean addClient(String deviceAddr, TcpDeviceClient client) { 108 public boolean addClient(String deviceAddr, TcpDeviceClient client) {
  109 + // TODO @haohao:这个要不去掉;目前看着没做 result 的处理;
109 if (clientMap.size() >= MAX_CONNECTIONS) { 110 if (clientMap.size() >= MAX_CONNECTIONS) {
110 log.warn("[addClient][连接数已达上限({}),拒绝新连接: {}]", MAX_CONNECTIONS, deviceAddr); 111 log.warn("[addClient][连接数已达上限({}),拒绝新连接: {}]", MAX_CONNECTIONS, deviceAddr);
111 return false; 112 return false;
@@ -130,14 +131,13 @@ public class TcpDeviceConnectionManager { @@ -130,14 +131,13 @@ public class TcpDeviceConnectionManager {
130 socketToAddrMap.put(client.getSocket(), deviceAddr); 131 socketToAddrMap.put(client.getSocket(), deviceAddr);
131 } 132 }
132 133
133 - // 如果客户端已设置设备ID,更新映射 134 + // 如果客户端已设置设备 ID,更新映射
134 if (client.getDeviceId() != null) { 135 if (client.getDeviceId() != null) {
135 deviceIdToAddrMap.put(client.getDeviceId(), deviceAddr); 136 deviceIdToAddrMap.put(client.getDeviceId(), deviceAddr);
136 } 137 }
137 138
138 totalConnections.incrementAndGet(); 139 totalConnections.incrementAndGet();
139 return true; 140 return true;
140 -  
141 } finally { 141 } finally {
142 writeLock.unlock(); 142 writeLock.unlock();
143 } 143 }
@@ -196,7 +196,7 @@ public class TcpDeviceConnectionManager { @@ -196,7 +196,7 @@ public class TcpDeviceConnectionManager {
196 } 196 }
197 197
198 /** 198 /**
199 - * 通过设备ID获取客户端 199 + * 通过设备 ID 获取客户端
200 */ 200 */
201 public TcpDeviceClient getClientByDeviceId(Long deviceId) { 201 public TcpDeviceClient getClientByDeviceId(Long deviceId) {
202 readLock.lock(); 202 readLock.lock();
@@ -208,6 +208,8 @@ public class TcpDeviceConnectionManager { @@ -208,6 +208,8 @@ public class TcpDeviceConnectionManager {
208 } 208 }
209 } 209 }
210 210
  211 + // TODO @haohao:getClientBySocket、isDeviceOnline、sendMessage、sendMessageByDeviceId、broadcastMessage 用不到的方法,要不先暂时不提供?保持简洁、更容易理解哈。
  212 +
211 /** 213 /**
212 * 通过网络连接获取客户端 214 * 通过网络连接获取客户端
213 */ 215 */
@@ -230,7 +232,7 @@ public class TcpDeviceConnectionManager { @@ -230,7 +232,7 @@ public class TcpDeviceConnectionManager {
230 } 232 }
231 233
232 /** 234 /**
233 - * 设置设备ID映射 235 + * 设置设备 ID 映射
234 */ 236 */
235 public void setDeviceIdMapping(String deviceAddr, Long deviceId) { 237 public void setDeviceIdMapping(String deviceAddr, Long deviceId) {
236 writeLock.lock(); 238 writeLock.lock();
@@ -349,12 +351,12 @@ public class TcpDeviceConnectionManager { @@ -349,12 +351,12 @@ public class TcpDeviceConnectionManager {
349 } 351 }
350 } 352 }
351 353
  354 + // TODO @haohao:心跳超时,需要 close 么?
352 /** 355 /**
353 * 心跳检查任务 356 * 心跳检查任务
354 */ 357 */
355 private void checkHeartbeat() { 358 private void checkHeartbeat() {
356 try { 359 try {
357 - long currentTime = System.currentTimeMillis();  
358 int offlineCount = 0; 360 int offlineCount = 0;
359 361
360 readLock.lock(); 362 readLock.lock();
@@ -369,7 +371,7 @@ public class TcpDeviceConnectionManager { @@ -369,7 +371,7 @@ public class TcpDeviceConnectionManager {
369 } 371 }
370 372
371 if (offlineCount > 0) { 373 if (offlineCount > 0) {
372 - log.info("[checkHeartbeat][发现{}个离线设备,将在清理任务中处理]", offlineCount); 374 + log.info("[checkHeartbeat][发现 {} 个离线设备,将在清理任务中处理]", offlineCount);
373 } 375 }
374 } catch (Exception e) { 376 } catch (Exception e) {
375 log.error("[checkHeartbeat][心跳检查任务异常]", e); 377 log.error("[checkHeartbeat][心跳检查任务异常]", e);
@@ -424,14 +426,14 @@ public class TcpDeviceConnectionManager { @@ -424,14 +426,14 @@ public class TcpDeviceConnectionManager {
424 private void logStatistics() { 426 private void logStatistics() {
425 try { 427 try {
426 long totalConn = totalConnections.get(); 428 long totalConn = totalConnections.get();
427 - long totalDisconn = totalDisconnections.get(); 429 + long totalDisconnections = this.totalDisconnections.get();
428 long totalMsg = totalMessages.get(); 430 long totalMsg = totalMessages.get();
429 long totalFailedMsg = totalFailedMessages.get(); 431 long totalFailedMsg = totalFailedMessages.get();
430 long totalBytesValue = totalBytes.get(); 432 long totalBytesValue = totalBytes.get();
431 433
432 log.info("[logStatistics][连接统计] 总连接: {}, 总断开: {}, 当前在线: {}, 认证设备: {}, " + 434 log.info("[logStatistics][连接统计] 总连接: {}, 总断开: {}, 当前在线: {}, 认证设备: {}, " +
433 "总消息: {}, 失败消息: {}, 总字节: {}", 435 "总消息: {}, 失败消息: {}, 总字节: {}",
434 - totalConn, totalDisconn, getOnlineCount(), getAuthenticatedCount(), 436 + totalConn, totalDisconnections, getOnlineCount(), getAuthenticatedCount(),
435 totalMsg, totalFailedMsg, totalBytesValue); 437 totalMsg, totalFailedMsg, totalBytesValue);
436 } catch (Exception e) { 438 } catch (Exception e) {
437 log.error("[logStatistics][统计日志任务异常]", e); 439 log.error("[logStatistics][统计日志任务异常]", e);
@@ -500,4 +502,5 @@ public class TcpDeviceConnectionManager { @@ -500,4 +502,5 @@ public class TcpDeviceConnectionManager {
500 ? (double) (totalMessages.get() - totalFailedMessages.get()) / totalMessages.get() * 100 502 ? (double) (totalMessages.get() - totalFailedMessages.get()) / totalMessages.get() * 100
501 : 0.0); 503 : 0.0);
502 } 504 }
  505 +
503 } 506 }
504 \ No newline at end of file 507 \ No newline at end of file
yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/tcp/protocol/TcpDataDecoder.java
@@ -3,13 +3,14 @@ package cn.iocoder.yudao.module.iot.gateway.protocol.tcp.protocol; @@ -3,13 +3,14 @@ package cn.iocoder.yudao.module.iot.gateway.protocol.tcp.protocol;
3 import io.vertx.core.buffer.Buffer; 3 import io.vertx.core.buffer.Buffer;
4 import lombok.extern.slf4j.Slf4j; 4 import lombok.extern.slf4j.Slf4j;
5 5
  6 +// TODO @haohao:“设备地址长度”是不是不需要。
6 /** 7 /**
7 * TCP 数据解码器 8 * TCP 数据解码器
8 * <p> 9 * <p>
9 * 负责将字节流解码为 TcpDataPackage 对象 10 * 负责将字节流解码为 TcpDataPackage 对象
10 * <p> 11 * <p>
11 * 数据包格式: 12 * 数据包格式:
12 - * 包头(4字节长度) | 设备地址长度(2字节) | 设备地址(不定长) | 功能码(2字节) | 消息序号(2字节) | 包体(不定长) 13 + * 包头(4 字节长度) | 设备地址长度(2 字节) | 设备地址(不定长) | 功能码(2 字节) | 消息序号(2 字节) | 包体(不定长)
13 * 14 *
14 * @author 芋道源码 15 * @author 芋道源码
15 */ 16 */
@@ -31,35 +32,35 @@ public class TcpDataDecoder { @@ -31,35 +32,35 @@ public class TcpDataDecoder {
31 try { 32 try {
32 int index = 0; 33 int index = 0;
33 34
34 - // 1. 获取设备地址长度(2字节) 35 + // 1.1 获取设备地址长度(2字节)
35 short addrLength = buffer.getShort(index); 36 short addrLength = buffer.getShort(index);
36 index += 2; 37 index += 2;
37 38
38 - // 2. 校验数据包长度 39 + // 1.2 校验数据包长度
39 int expectedLength = 2 + addrLength + 2 + 2; // 地址长度 + 地址 + 功能码 + 消息序号 40 int expectedLength = 2 + addrLength + 2 + 2; // 地址长度 + 地址 + 功能码 + 消息序号
40 if (buffer.length() < expectedLength) { 41 if (buffer.length() < expectedLength) {
41 throw new IllegalArgumentException("数据包长度不足,期望至少 " + expectedLength + " 字节"); 42 throw new IllegalArgumentException("数据包长度不足,期望至少 " + expectedLength + " 字节");
42 } 43 }
43 44
44 - // 3. 获取设备地址 45 + // 1.3 获取设备地址
45 String addr = buffer.getBuffer(index, index + addrLength).toString(); 46 String addr = buffer.getBuffer(index, index + addrLength).toString();
46 index += addrLength; 47 index += addrLength;
47 48
48 - // 4. 获取功能码(2字节) 49 + // 1.4 获取功能码(2字节)
49 short code = buffer.getShort(index); 50 short code = buffer.getShort(index);
50 index += 2; 51 index += 2;
51 52
52 - // 5. 获取消息序号(2字节) 53 + // 1.5 获取消息序号(2字节)
53 short mid = buffer.getShort(index); 54 short mid = buffer.getShort(index);
54 index += 2; 55 index += 2;
55 56
56 - // 6. 获取包体数据 57 + // 1.6 获取包体数据
57 String payload = ""; 58 String payload = "";
58 if (index < buffer.length()) { 59 if (index < buffer.length()) {
59 payload = buffer.getString(index, buffer.length()); 60 payload = buffer.getString(index, buffer.length());
60 } 61 }
61 62
62 - // 7. 构建数据包对象 63 + // 2. 构建数据包对象
63 TcpDataPackage dataPackage = TcpDataPackage.builder() 64 TcpDataPackage dataPackage = TcpDataPackage.builder()
64 .addrLength((int) addrLength) 65 .addrLength((int) addrLength)
65 .addr(addr) 66 .addr(addr)
@@ -70,15 +71,14 @@ public class TcpDataDecoder { @@ -70,15 +71,14 @@ public class TcpDataDecoder {
70 71
71 log.debug("[decode][解码成功] 设备地址: {}, 功能码: {}, 消息序号: {}, 包体长度: {}", 72 log.debug("[decode][解码成功] 设备地址: {}, 功能码: {}, 消息序号: {}, 包体长度: {}",
72 addr, dataPackage.getCodeDescription(), mid, payload.length()); 73 addr, dataPackage.getCodeDescription(), mid, payload.length());
73 -  
74 return dataPackage; 74 return dataPackage;
75 -  
76 } catch (Exception e) { 75 } catch (Exception e) {
77 log.error("[decode][解码失败] 数据: {}", buffer.toString(), e); 76 log.error("[decode][解码失败] 数据: {}", buffer.toString(), e);
78 throw new IllegalArgumentException("数据包解码失败: " + e.getMessage(), e); 77 throw new IllegalArgumentException("数据包解码失败: " + e.getMessage(), e);
79 } 78 }
80 } 79 }
81 80
  81 + // TODO @haohao:这个要不去掉,暂时没用到;
82 /** 82 /**
83 * 校验数据包格式 83 * 校验数据包格式
84 * 84 *
@@ -94,4 +94,5 @@ public class TcpDataDecoder { @@ -94,4 +94,5 @@ public class TcpDataDecoder {
94 return false; 94 return false;
95 } 95 }
96 } 96 }
  97 +
97 } 98 }
98 \ No newline at end of file 99 \ No newline at end of file
yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/tcp/protocol/TcpDataEncoder.java
@@ -27,11 +27,9 @@ public class TcpDataEncoder { @@ -27,11 +27,9 @@ public class TcpDataEncoder {
27 if (dataPackage == null) { 27 if (dataPackage == null) {
28 throw new IllegalArgumentException("数据包对象不能为空"); 28 throw new IllegalArgumentException("数据包对象不能为空");
29 } 29 }
30 -  
31 if (dataPackage.getAddr() == null || dataPackage.getAddr().isEmpty()) { 30 if (dataPackage.getAddr() == null || dataPackage.getAddr().isEmpty()) {
32 throw new IllegalArgumentException("设备地址不能为空"); 31 throw new IllegalArgumentException("设备地址不能为空");
33 } 32 }
34 -  
35 if (dataPackage.getPayload() == null) { 33 if (dataPackage.getPayload() == null) {
36 dataPackage.setPayload(""); 34 dataPackage.setPayload("");
37 } 35 }
@@ -39,34 +37,27 @@ public class TcpDataEncoder { @@ -39,34 +37,27 @@ public class TcpDataEncoder {
39 try { 37 try {
40 Buffer buffer = Buffer.buffer(); 38 Buffer buffer = Buffer.buffer();
41 39
42 - // 1. 计算包体长度(除了包头4字节) 40 + // 1. 计算包体长度(除了包头 4 字节)
43 int payloadLength = dataPackage.getPayload().getBytes().length; 41 int payloadLength = dataPackage.getPayload().getBytes().length;
44 int totalLength = 2 + dataPackage.getAddr().length() + 2 + 2 + payloadLength; 42 int totalLength = 2 + dataPackage.getAddr().length() + 2 + 2 + payloadLength;
45 43
46 - // 2. 写入包头:总长度(4字节) 44 + // 2.1 写入包头:总长度(4 字节)
47 buffer.appendInt(totalLength); 45 buffer.appendInt(totalLength);
48 -  
49 - // 3. 写入设备地址长度(2字节) 46 + // 2.2 写入设备地址长度(2 字节)
50 buffer.appendShort((short) dataPackage.getAddr().length()); 47 buffer.appendShort((short) dataPackage.getAddr().length());
51 -  
52 - // 4. 写入设备地址(不定长) 48 + // 2.3 写入设备地址(不定长)
53 buffer.appendBytes(dataPackage.getAddr().getBytes()); 49 buffer.appendBytes(dataPackage.getAddr().getBytes());
54 -  
55 - // 5. 写入功能码(2字节) 50 + // 2.4 写入功能码(2 字节)
56 buffer.appendShort(dataPackage.getCode()); 51 buffer.appendShort(dataPackage.getCode());
57 -  
58 - // 6. 写入消息序号(2字节) 52 + // 2.5 写入消息序号(2 字节)
59 buffer.appendShort(dataPackage.getMid()); 53 buffer.appendShort(dataPackage.getMid());
60 -  
61 - // 7. 写入包体数据(不定长) 54 + // 2.6 写入包体数据(不定长)
62 buffer.appendBytes(dataPackage.getPayload().getBytes()); 55 buffer.appendBytes(dataPackage.getPayload().getBytes());
63 56
64 log.debug("[encode][编码成功] 设备地址: {}, 功能码: {}, 消息序号: {}, 总长度: {}", 57 log.debug("[encode][编码成功] 设备地址: {}, 功能码: {}, 消息序号: {}, 总长度: {}",
65 dataPackage.getAddr(), dataPackage.getCodeDescription(), 58 dataPackage.getAddr(), dataPackage.getCodeDescription(),
66 dataPackage.getMid(), buffer.length()); 59 dataPackage.getMid(), buffer.length());
67 -  
68 return buffer; 60 return buffer;
69 -  
70 } catch (Exception e) { 61 } catch (Exception e) {
71 log.error("[encode][编码失败] 数据包: {}", dataPackage, e); 62 log.error("[encode][编码失败] 数据包: {}", dataPackage, e);
72 throw new IllegalArgumentException("数据包编码失败: " + e.getMessage(), e); 63 throw new IllegalArgumentException("数据包编码失败: " + e.getMessage(), e);
@@ -82,15 +73,14 @@ public class TcpDataEncoder { @@ -82,15 +73,14 @@ public class TcpDataEncoder {
82 * @return 编码后的数据包 73 * @return 编码后的数据包
83 */ 74 */
84 public static Buffer createRegisterReply(String addr, short mid, boolean success) { 75 public static Buffer createRegisterReply(String addr, short mid, boolean success) {
85 - String payload = success ? "0" : "1"; // 0表示成功,1表示失败  
86 - 76 + // TODO @haohao:payload 默认成功、失败,最好讴有个枚举
  77 + String payload = success ? "0" : "1"; // 0 表示成功,1 表示失败
87 TcpDataPackage dataPackage = TcpDataPackage.builder() 78 TcpDataPackage dataPackage = TcpDataPackage.builder()
88 .addr(addr) 79 .addr(addr)
89 .code(TcpDataPackage.CODE_REGISTER_REPLY) 80 .code(TcpDataPackage.CODE_REGISTER_REPLY)
90 .mid(mid) 81 .mid(mid)
91 .payload(payload) 82 .payload(payload)
92 .build(); 83 .build();
93 -  
94 return encode(dataPackage); 84 return encode(dataPackage);
95 } 85 }
96 86
@@ -109,7 +99,6 @@ public class TcpDataEncoder { @@ -109,7 +99,6 @@ public class TcpDataEncoder {
109 .mid(mid) 99 .mid(mid)
110 .payload(data) 100 .payload(data)
111 .build(); 101 .build();
112 -  
113 return encode(dataPackage); 102 return encode(dataPackage);
114 } 103 }
115 104
@@ -128,7 +117,6 @@ public class TcpDataEncoder { @@ -128,7 +117,6 @@ public class TcpDataEncoder {
128 .mid(mid) 117 .mid(mid)
129 .payload(serviceData) 118 .payload(serviceData)
130 .build(); 119 .build();
131 -  
132 return encode(dataPackage); 120 return encode(dataPackage);
133 } 121 }
134 122
@@ -147,7 +135,6 @@ public class TcpDataEncoder { @@ -147,7 +135,6 @@ public class TcpDataEncoder {
147 .mid(mid) 135 .mid(mid)
148 .payload(propertyData) 136 .payload(propertyData)
149 .build(); 137 .build();
150 -  
151 return encode(dataPackage); 138 return encode(dataPackage);
152 } 139 }
153 140
@@ -166,7 +153,7 @@ public class TcpDataEncoder { @@ -166,7 +153,7 @@ public class TcpDataEncoder {
166 .mid(mid) 153 .mid(mid)
167 .payload(propertyNames) 154 .payload(propertyNames)
168 .build(); 155 .build();
169 -  
170 return encode(dataPackage); 156 return encode(dataPackage);
171 } 157 }
  158 +
172 } 159 }
173 \ No newline at end of file 160 \ No newline at end of file
yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/tcp/protocol/TcpDataPackage.java
@@ -9,7 +9,7 @@ import lombok.NoArgsConstructor; @@ -9,7 +9,7 @@ import lombok.NoArgsConstructor;
9 * TCP 数据包协议定义 9 * TCP 数据包协议定义
10 * <p> 10 * <p>
11 * 数据包格式: 11 * 数据包格式:
12 - * 包头(4字节长度) | 设备地址长度(2字节) | 设备地址(不定长) | 功能码(2字节) | 消息序号(2字节) | 包体(不定长) 12 + * 包头(4 字节长度) | 设备地址长度(2 字节) | 设备地址(不定长) | 功能码(2 字节) | 消息序号(2 字节) | 包体(不定长)
13 * 13 *
14 * @author 芋道源码 14 * @author 芋道源码
15 */ 15 */
@@ -29,10 +29,12 @@ public class TcpDataPackage { @@ -29,10 +29,12 @@ public class TcpDataPackage {
29 * 注册回复 29 * 注册回复
30 */ 30 */
31 public static final short CODE_REGISTER_REPLY = 11; 31 public static final short CODE_REGISTER_REPLY = 11;
  32 + // TODO @haohao:【重要】一般心跳,服务端会回复一条;回复要搞独立的 code 码,还是继续用原来的,因为 requestId 可以映射;
32 /** 33 /**
33 * 心跳 34 * 心跳
34 */ 35 */
35 public static final short CODE_HEARTBEAT = 20; 36 public static final short CODE_HEARTBEAT = 20;
  37 + // TODO @haohao:【重要】下面的,是不是融合成消息上行(client -> server),消息下行(server -> client);然后把 method 放到 body 里?
36 /** 38 /**
37 * 数据上报 39 * 数据上报
38 */ 40 */
@@ -60,6 +62,8 @@ public class TcpDataPackage { @@ -60,6 +62,8 @@ public class TcpDataPackage {
60 62
61 // ==================== 数据包字段 ==================== 63 // ==================== 数据包字段 ====================
62 64
  65 + // TODO @haohao:设备 addrLength、addr 是不是非必要呀?
  66 +
63 /** 67 /**
64 * 设备地址长度 68 * 设备地址长度
65 */ 69 */
@@ -87,6 +91,8 @@ public class TcpDataPackage { @@ -87,6 +91,8 @@ public class TcpDataPackage {
87 91
88 // ==================== 辅助方法 ==================== 92 // ==================== 辅助方法 ====================
89 93
  94 + // TODO @haohao:用不到的方法,可以清理掉哈;
  95 +
90 /** 96 /**
91 * 是否为注册消息 97 * 是否为注册消息
92 */ 98 */
@@ -123,6 +129,7 @@ public class TcpDataPackage { @@ -123,6 +129,7 @@ public class TcpDataPackage {
123 code == CODE_PROPERTY_SET || code == CODE_PROPERTY_GET; 129 code == CODE_PROPERTY_SET || code == CODE_PROPERTY_GET;
124 } 130 }
125 131
  132 + // TODO @haohao:这个是不是去掉呀?多了一些维护成本;
126 /** 133 /**
127 * 获取功能码描述 134 * 获取功能码描述
128 */ 135 */
yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/tcp/protocol/TcpDataReader.java
@@ -13,7 +13,7 @@ import java.util.function.Consumer; @@ -13,7 +13,7 @@ import java.util.function.Consumer;
13 * 负责从 TCP 流中读取完整的数据包 13 * 负责从 TCP 流中读取完整的数据包
14 * <p> 14 * <p>
15 * 数据包格式: 15 * 数据包格式:
16 - * 包头(4字节长度) | 设备地址长度(2字节) | 设备地址(不定长) | 功能码(2字节) | 消息序号(2字节) | 包体(不定长) 16 + * 包头(4 字节长度) | 设备地址长度(2 字节) | 设备地址(不定长) | 功能码(2 字节) | 消息序号(2 字节) | 包体(不定长)
17 * 17 *
18 * @author 芋道源码 18 * @author 芋道源码
19 */ 19 */
@@ -27,12 +27,12 @@ public class TcpDataReader { @@ -27,12 +27,12 @@ public class TcpDataReader {
27 * @return RecordParser 解析器 27 * @return RecordParser 解析器
28 */ 28 */
29 public static RecordParser createParser(Consumer<Buffer> receiveHandler) { 29 public static RecordParser createParser(Consumer<Buffer> receiveHandler) {
30 - // 首先读取4字节的长度信息 30 + // 首先读取 4 字节的长度信息
31 RecordParser parser = RecordParser.newFixed(4); 31 RecordParser parser = RecordParser.newFixed(4);
32 32
33 // 设置处理器 33 // 设置处理器
34 parser.setOutput(new Handler<Buffer>() { 34 parser.setOutput(new Handler<Buffer>() {
35 - // 当前数据包的长度,-1表示还没有读取到长度信息 35 + // 当前数据包的长度,-1 表示还没有读取到长度信息
36 private int dataLength = -1; 36 private int dataLength = -1;
37 37
38 @Override 38 @Override
@@ -43,8 +43,9 @@ public class TcpDataReader { @@ -43,8 +43,9 @@ public class TcpDataReader {
43 // 从包头中读取数据长度 43 // 从包头中读取数据长度
44 dataLength = buffer.getInt(0); 44 dataLength = buffer.getInt(0);
45 45
46 - // 校验数据长度  
47 - if (dataLength <= 0 || dataLength > 1024 * 1024) { // 最大1MB 46 + // 校验数据长度(最大 1 MB)
  47 + // TODO @haohao:1m 蛮多地方在写死,最好配置管理下。或者有个全局的枚举;
  48 + if (dataLength <= 0 || dataLength > 1024 * 1024) {
48 log.error("[handle][无效的数据包长度: {}]", dataLength); 49 log.error("[handle][无效的数据包长度: {}]", dataLength);
49 reset(); 50 reset();
50 return; 51 return;
@@ -86,6 +87,8 @@ public class TcpDataReader { @@ -86,6 +87,8 @@ public class TcpDataReader {
86 return parser; 87 return parser;
87 } 88 }
88 89
  90 + // TODO @haohao:用不到的方法,可以清理掉哈;
  91 +
89 /** 92 /**
90 * 创建带异常处理的数据包解析器 93 * 创建带异常处理的数据包解析器
91 * 94 *
yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/tcp/router/IotTcpDownstreamHandler.java
@@ -55,6 +55,7 @@ public class IotTcpDownstreamHandler { @@ -55,6 +55,7 @@ public class IotTcpDownstreamHandler {
55 } 55 }
56 56
57 // 2. 根据消息方法处理不同类型的下行消息 57 // 2. 根据消息方法处理不同类型的下行消息
  58 + // TODO @芋艿、@haohao:看看有没什么办法,减少这样的编码。拓展新消息类型,成本高;
58 switch (message.getMethod()) { 59 switch (message.getMethod()) {
59 case "thing.property.set": 60 case "thing.property.set":
60 handlePropertySet(client, message); 61 handlePropertySet(client, message);
@@ -75,8 +76,8 @@ public class IotTcpDownstreamHandler { @@ -75,8 +76,8 @@ public class IotTcpDownstreamHandler {
75 log.warn("[handle][未知的下行消息方法: {}]", message.getMethod()); 76 log.warn("[handle][未知的下行消息方法: {}]", message.getMethod());
76 break; 77 break;
77 } 78 }
78 -  
79 } catch (Exception e) { 79 } catch (Exception e) {
  80 + // TODO @haohao:最好消息的内容,打印下;
80 log.error("[handle][处理下行消息失败]", e); 81 log.error("[handle][处理下行消息失败]", e);
81 } 82 }
82 } 83 }
@@ -104,7 +105,6 @@ public class IotTcpDownstreamHandler { @@ -104,7 +105,6 @@ public class IotTcpDownstreamHandler {
104 log.debug("[handlePropertySet][属性设置消息已发送(降级)] 设备地址: {}, 消息序号: {}", 105 log.debug("[handlePropertySet][属性设置消息已发送(降级)] 设备地址: {}, 消息序号: {}",
105 client.getDeviceAddr(), mid); 106 client.getDeviceAddr(), mid);
106 }); 107 });
107 -  
108 } catch (Exception e) { 108 } catch (Exception e) {
109 log.error("[handlePropertySet][属性设置失败]", e); 109 log.error("[handlePropertySet][属性设置失败]", e);
110 } 110 }
@@ -133,7 +133,6 @@ public class IotTcpDownstreamHandler { @@ -133,7 +133,6 @@ public class IotTcpDownstreamHandler {
133 log.debug("[handlePropertyGet][属性获取消息已发送(降级)] 设备地址: {}, 消息序号: {}", 133 log.debug("[handlePropertyGet][属性获取消息已发送(降级)] 设备地址: {}, 消息序号: {}",
134 client.getDeviceAddr(), mid); 134 client.getDeviceAddr(), mid);
135 }); 135 });
136 -  
137 } catch (Exception e) { 136 } catch (Exception e) {
138 log.error("[handlePropertyGet][属性获取失败]", e); 137 log.error("[handlePropertyGet][属性获取失败]", e);
139 } 138 }
@@ -162,7 +161,6 @@ public class IotTcpDownstreamHandler { @@ -162,7 +161,6 @@ public class IotTcpDownstreamHandler {
162 161
163 log.debug("[handleServiceInvoke][服务调用消息已发送] 设备地址: {}, 消息序号: {}", 162 log.debug("[handleServiceInvoke][服务调用消息已发送] 设备地址: {}, 消息序号: {}",
164 client.getDeviceAddr(), mid); 163 client.getDeviceAddr(), mid);
165 -  
166 } catch (Exception e) { 164 } catch (Exception e) {
167 log.error("[handleServiceInvoke][服务调用失败]", e); 165 log.error("[handleServiceInvoke][服务调用失败]", e);
168 } 166 }
@@ -191,7 +189,6 @@ public class IotTcpDownstreamHandler { @@ -191,7 +189,6 @@ public class IotTcpDownstreamHandler {
191 189
192 log.debug("[handleConfigPush][配置推送消息已发送] 设备地址: {}, 消息序号: {}", 190 log.debug("[handleConfigPush][配置推送消息已发送] 设备地址: {}, 消息序号: {}",
193 client.getDeviceAddr(), mid); 191 client.getDeviceAddr(), mid);
194 -  
195 } catch (Exception e) { 192 } catch (Exception e) {
196 log.error("[handleConfigPush][配置推送失败]", e); 193 log.error("[handleConfigPush][配置推送失败]", e);
197 } 194 }
@@ -262,6 +259,7 @@ public class IotTcpDownstreamHandler { @@ -262,6 +259,7 @@ public class IotTcpDownstreamHandler {
262 } 259 }
263 } 260 }
264 261
  262 + // TODO @haohao:用不到的,要不暂时不提供;
265 /** 263 /**
266 * 批量发送下行消息 264 * 批量发送下行消息
267 * 265 *
@@ -287,7 +285,6 @@ public class IotTcpDownstreamHandler { @@ -287,7 +285,6 @@ public class IotTcpDownstreamHandler {
287 // 处理单个设备消息 285 // 处理单个设备消息
288 handle(copyMessage); 286 handle(copyMessage);
289 } 287 }
290 -  
291 } catch (Exception e) { 288 } catch (Exception e) {
292 log.error("[broadcastMessage][批量发送消息失败]", e); 289 log.error("[broadcastMessage][批量发送消息失败]", e);
293 } 290 }
@@ -341,7 +338,6 @@ public class IotTcpDownstreamHandler { @@ -341,7 +338,6 @@ public class IotTcpDownstreamHandler {
341 338
342 log.debug("[{}][消息已发送] 设备地址: {}, 消息序号: {}", 339 log.debug("[{}][消息已发送] 设备地址: {}, 消息序号: {}",
343 methodName, client.getDeviceAddr(), dataPackage.getMid()); 340 methodName, client.getDeviceAddr(), dataPackage.getMid());
344 -  
345 } catch (Exception e) { 341 } catch (Exception e) {
346 log.warn("[{}][使用编解码器编码失败,降级使用原始编码] 错误: {}", 342 log.warn("[{}][使用编解码器编码失败,降级使用原始编码] 错误: {}",
347 methodName, e.getMessage()); 343 methodName, e.getMessage());
@@ -353,6 +349,7 @@ public class IotTcpDownstreamHandler { @@ -353,6 +349,7 @@ public class IotTcpDownstreamHandler {
353 } 349 }
354 } 350 }
355 351
  352 + // TODO @haohao:看看这个要不要删除掉
356 /** 353 /**
357 * 获取连接统计信息 354 * 获取连接统计信息
358 * 355 *
yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/tcp/router/IotTcpUpstreamHandler.java
@@ -39,6 +39,7 @@ public class IotTcpUpstreamHandler implements Handler&lt;NetSocket&gt; { @@ -39,6 +39,7 @@ public class IotTcpUpstreamHandler implements Handler&lt;NetSocket&gt; {
39 39
40 private final IotGatewayProperties.TcpProperties tcpConfig; 40 private final IotGatewayProperties.TcpProperties tcpConfig;
41 41
  42 + // TODO @haohao:可以把 TcpDeviceConnectionManager 能力放大一点:1)handle 里的 client 初始化,可以拿到 TcpDeviceConnectionManager 里;2)handleDeviceRegister 也是;
42 private final TcpDeviceConnectionManager connectionManager; 43 private final TcpDeviceConnectionManager connectionManager;
43 44
44 private final IotDeviceService deviceService; 45 private final IotDeviceService deviceService;
@@ -53,26 +54,25 @@ public class IotTcpUpstreamHandler implements Handler&lt;NetSocket&gt; { @@ -53,26 +54,25 @@ public class IotTcpUpstreamHandler implements Handler&lt;NetSocket&gt; {
53 public void handle(NetSocket socket) { 54 public void handle(NetSocket socket) {
54 log.info("[handle][收到设备连接: {}]", socket.remoteAddress()); 55 log.info("[handle][收到设备连接: {}]", socket.remoteAddress());
55 56
56 - // 创建客户端ID和设备客户端 57 + // 创建客户端 ID 和设备客户端
  58 + // TODO @haohao:clientid 给 TcpDeviceClient 生成会简洁一点;减少 upsteramhanlder 的非核心逻辑;
57 String clientId = IdUtil.simpleUUID() + "_" + socket.remoteAddress(); 59 String clientId = IdUtil.simpleUUID() + "_" + socket.remoteAddress();
58 TcpDeviceClient client = new TcpDeviceClient(clientId, tcpConfig.getKeepAliveTimeoutMs()); 60 TcpDeviceClient client = new TcpDeviceClient(clientId, tcpConfig.getKeepAliveTimeoutMs());
59 61
60 try { 62 try {
61 // 设置连接异常和关闭处理 63 // 设置连接异常和关闭处理
62 socket.exceptionHandler(ex -> { 64 socket.exceptionHandler(ex -> {
  65 + // TODO @haohao:这里的日志,可能把 clientid 都打上?因为 address 会重复么?
63 log.error("[handle][连接({})异常]", socket.remoteAddress(), ex); 66 log.error("[handle][连接({})异常]", socket.remoteAddress(), ex);
64 handleConnectionClose(client); 67 handleConnectionClose(client);
65 }); 68 });
66 -  
67 socket.closeHandler(v -> { 69 socket.closeHandler(v -> {
68 log.info("[handle][连接({})关闭]", socket.remoteAddress()); 70 log.info("[handle][连接({})关闭]", socket.remoteAddress());
69 handleConnectionClose(client); 71 handleConnectionClose(client);
70 }); 72 });
71 -  
72 - // 设置网络连接  
73 client.setSocket(socket); 73 client.setSocket(socket);
74 74
75 - // 创建数据解析器 75 + // 设置解析器
76 RecordParser parser = TcpDataReader.createParser(buffer -> { 76 RecordParser parser = TcpDataReader.createParser(buffer -> {
77 try { 77 try {
78 handleDataPackage(client, buffer); 78 handleDataPackage(client, buffer);
@@ -80,13 +80,12 @@ public class IotTcpUpstreamHandler implements Handler&lt;NetSocket&gt; { @@ -80,13 +80,12 @@ public class IotTcpUpstreamHandler implements Handler&lt;NetSocket&gt; {
80 log.error("[handle][处理数据包异常]", e); 80 log.error("[handle][处理数据包异常]", e);
81 } 81 }
82 }); 82 });
83 -  
84 - // 设置解析器  
85 client.setParser(parser); 83 client.setParser(parser);
86 84
  85 + // TODO @haohao:socket.remoteAddress()) 打印进去
87 log.info("[handle][设备连接处理器初始化完成: {}]", clientId); 86 log.info("[handle][设备连接处理器初始化完成: {}]", clientId);
88 -  
89 } catch (Exception e) { 87 } catch (Exception e) {
  88 + // TODO @haohao:socket.remoteAddress()) 打印进去
90 log.error("[handle][初始化连接处理器失败]", e); 89 log.error("[handle][初始化连接处理器失败]", e);
91 client.shutdown(); 90 client.shutdown();
92 } 91 }
@@ -102,12 +101,12 @@ public class IotTcpUpstreamHandler implements Handler&lt;NetSocket&gt; { @@ -102,12 +101,12 @@ public class IotTcpUpstreamHandler implements Handler&lt;NetSocket&gt; {
102 try { 101 try {
103 // 解码数据包 102 // 解码数据包
104 TcpDataPackage dataPackage = TcpDataDecoder.decode(buffer); 103 TcpDataPackage dataPackage = TcpDataDecoder.decode(buffer);
105 -  
106 log.info("[handleDataPackage][接收数据包] 设备地址: {}, 功能码: {}, 消息序号: {}", 104 log.info("[handleDataPackage][接收数据包] 设备地址: {}, 功能码: {}, 消息序号: {}",
107 dataPackage.getAddr(), dataPackage.getCodeDescription(), dataPackage.getMid()); 105 dataPackage.getAddr(), dataPackage.getCodeDescription(), dataPackage.getMid());
108 106
109 // 根据功能码处理不同类型的消息 107 // 根据功能码处理不同类型的消息
110 switch (dataPackage.getCode()) { 108 switch (dataPackage.getCode()) {
  109 + // TODO @haohao:【重要】code 要不要改成 opCode。这样和 data 里的 code 好区分;
111 case TcpDataPackage.CODE_REGISTER: 110 case TcpDataPackage.CODE_REGISTER:
112 handleDeviceRegister(client, dataPackage); 111 handleDeviceRegister(client, dataPackage);
113 break; 112 break;
@@ -124,8 +123,8 @@ public class IotTcpUpstreamHandler implements Handler&lt;NetSocket&gt; { @@ -124,8 +123,8 @@ public class IotTcpUpstreamHandler implements Handler&lt;NetSocket&gt; {
124 log.warn("[handleDataPackage][未知功能码: {}]", dataPackage.getCode()); 123 log.warn("[handleDataPackage][未知功能码: {}]", dataPackage.getCode());
125 break; 124 break;
126 } 125 }
127 -  
128 } catch (Exception e) { 126 } catch (Exception e) {
  127 + // TODO @haohao:最好有 client 标识;
129 log.error("[handleDataPackage][处理数据包失败]", e); 128 log.error("[handleDataPackage][处理数据包失败]", e);
130 } 129 }
131 } 130 }
@@ -140,7 +139,6 @@ public class IotTcpUpstreamHandler implements Handler&lt;NetSocket&gt; { @@ -140,7 +139,6 @@ public class IotTcpUpstreamHandler implements Handler&lt;NetSocket&gt; {
140 try { 139 try {
141 String deviceAddr = dataPackage.getAddr(); 140 String deviceAddr = dataPackage.getAddr();
142 String productKey = dataPackage.getPayload(); 141 String productKey = dataPackage.getPayload();
143 -  
144 log.info("[handleDeviceRegister][设备注册] 设备地址: {}, 产品密钥: {}", deviceAddr, productKey); 142 log.info("[handleDeviceRegister][设备注册] 设备地址: {}, 产品密钥: {}", deviceAddr, productKey);
145 143
146 // 获取设备信息 144 // 获取设备信息
@@ -152,6 +150,7 @@ public class IotTcpUpstreamHandler implements Handler&lt;NetSocket&gt; { @@ -152,6 +150,7 @@ public class IotTcpUpstreamHandler implements Handler&lt;NetSocket&gt; {
152 } 150 }
153 151
154 // 更新客户端信息 152 // 更新客户端信息
  153 + // TODO @haohao:一个 set 方法,统一处理掉会好点哈;
155 client.setProductKey(productKey); 154 client.setProductKey(productKey);
156 client.setDeviceName(deviceAddr); 155 client.setDeviceName(deviceAddr);
157 client.setDeviceId(device.getId()); 156 client.setDeviceId(device.getId());
@@ -169,7 +168,6 @@ public class IotTcpUpstreamHandler implements Handler&lt;NetSocket&gt; { @@ -169,7 +168,6 @@ public class IotTcpUpstreamHandler implements Handler&lt;NetSocket&gt; {
169 sendRegisterReply(client, dataPackage, true); 168 sendRegisterReply(client, dataPackage, true);
170 169
171 log.info("[handleDeviceRegister][设备注册成功] 设备地址: {}, 设备ID: {}", deviceAddr, device.getId()); 170 log.info("[handleDeviceRegister][设备注册成功] 设备地址: {}, 设备ID: {}", deviceAddr, device.getId());
172 -  
173 } catch (Exception e) { 171 } catch (Exception e) {
174 log.error("[handleDeviceRegister][设备注册失败]", e); 172 log.error("[handleDeviceRegister][设备注册失败]", e);
175 sendRegisterReply(client, dataPackage, false); 173 sendRegisterReply(client, dataPackage, false);
@@ -185,7 +183,6 @@ public class IotTcpUpstreamHandler implements Handler&lt;NetSocket&gt; { @@ -185,7 +183,6 @@ public class IotTcpUpstreamHandler implements Handler&lt;NetSocket&gt; {
185 private void handleHeartbeat(TcpDeviceClient client, TcpDataPackage dataPackage) { 183 private void handleHeartbeat(TcpDeviceClient client, TcpDataPackage dataPackage) {
186 try { 184 try {
187 String deviceAddr = dataPackage.getAddr(); 185 String deviceAddr = dataPackage.getAddr();
188 -  
189 log.debug("[handleHeartbeat][收到心跳] 设备地址: {}", deviceAddr); 186 log.debug("[handleHeartbeat][收到心跳] 设备地址: {}", deviceAddr);
190 187
191 // 更新心跳时间 188 // 更新心跳时间
@@ -230,7 +227,6 @@ public class IotTcpUpstreamHandler implements Handler&lt;NetSocket&gt; { @@ -230,7 +227,6 @@ public class IotTcpUpstreamHandler implements Handler&lt;NetSocket&gt; {
230 227
231 // 3. 发送解码后的消息 228 // 3. 发送解码后的消息
232 messageService.sendDeviceMessage(message, client.getProductKey(), client.getDeviceName(), serverId); 229 messageService.sendDeviceMessage(message, client.getProductKey(), client.getDeviceName(), serverId);
233 -  
234 } catch (Exception e) { 230 } catch (Exception e) {
235 log.warn("[handleDataUp][使用编解码器解码失败,降级使用原始解析] 错误: {}", e.getMessage()); 231 log.warn("[handleDataUp][使用编解码器解码失败,降级使用原始解析] 错误: {}", e.getMessage());
236 232
@@ -242,7 +238,6 @@ public class IotTcpUpstreamHandler implements Handler&lt;NetSocket&gt; { @@ -242,7 +238,6 @@ public class IotTcpUpstreamHandler implements Handler&lt;NetSocket&gt; {
242 238
243 // 发送数据上报回复 239 // 发送数据上报回复
244 sendDataUpReply(client, dataPackage); 240 sendDataUpReply(client, dataPackage);
245 -  
246 } catch (Exception e) { 241 } catch (Exception e) {
247 log.error("[handleDataUp][处理数据上报失败]", e); 242 log.error("[handleDataUp][处理数据上报失败]", e);
248 } 243 }
@@ -279,11 +274,11 @@ public class IotTcpUpstreamHandler implements Handler&lt;NetSocket&gt; { @@ -279,11 +274,11 @@ public class IotTcpUpstreamHandler implements Handler&lt;NetSocket&gt; {
279 274
280 // 3. 发送解码后的消息 275 // 3. 发送解码后的消息
281 messageService.sendDeviceMessage(message, client.getProductKey(), client.getDeviceName(), serverId); 276 messageService.sendDeviceMessage(message, client.getProductKey(), client.getDeviceName(), serverId);
282 -  
283 } catch (Exception e) { 277 } catch (Exception e) {
284 log.warn("[handleEventUp][使用编解码器解码失败,降级使用原始解析] 错误: {}", e.getMessage()); 278 log.warn("[handleEventUp][使用编解码器解码失败,降级使用原始解析] 错误: {}", e.getMessage());
285 279
286 // 降级处理:使用原始方式解析数据 280 // 降级处理:使用原始方式解析数据
  281 + // TODO @芋艿:降级处理逻辑;
287 JSONObject eventJson = JSONUtil.parseObj(payload); 282 JSONObject eventJson = JSONUtil.parseObj(payload);
288 IotDeviceMessage message = IotDeviceMessage.requestOf("thing.event.post", eventJson); 283 IotDeviceMessage message = IotDeviceMessage.requestOf("thing.event.post", eventJson);
289 messageService.sendDeviceMessage(message, client.getProductKey(), client.getDeviceName(), serverId); 284 messageService.sendDeviceMessage(message, client.getProductKey(), client.getDeviceName(), serverId);
@@ -291,7 +286,6 @@ public class IotTcpUpstreamHandler implements Handler&lt;NetSocket&gt; { @@ -291,7 +286,6 @@ public class IotTcpUpstreamHandler implements Handler&lt;NetSocket&gt; {
291 286
292 // 发送事件上报回复 287 // 发送事件上报回复
293 sendEventUpReply(client, dataPackage); 288 sendEventUpReply(client, dataPackage);
294 -  
295 } catch (Exception e) { 289 } catch (Exception e) {
296 log.error("[handleEventUp][处理事件上报失败]", e); 290 log.error("[handleEventUp][处理事件上报失败]", e);
297 } 291 }
@@ -329,13 +323,13 @@ public class IotTcpUpstreamHandler implements Handler&lt;NetSocket&gt; { @@ -329,13 +323,13 @@ public class IotTcpUpstreamHandler implements Handler&lt;NetSocket&gt; {
329 .addr(dataPackage.getAddr()) 323 .addr(dataPackage.getAddr())
330 .code(TcpDataPackage.CODE_DATA_UP) 324 .code(TcpDataPackage.CODE_DATA_UP)
331 .mid(dataPackage.getMid()) 325 .mid(dataPackage.getMid())
332 - .payload("0") // 0表示成功 326 + .payload("0") // 0 表示成功 TODO @haohao:最好枚举到 TcpDataPackage 里?
333 .build(); 327 .build();
334 328
335 io.vertx.core.buffer.Buffer replyBuffer = TcpDataEncoder.encode(replyPackage); 329 io.vertx.core.buffer.Buffer replyBuffer = TcpDataEncoder.encode(replyPackage);
336 client.sendMessage(replyBuffer); 330 client.sendMessage(replyBuffer);
337 -  
338 } catch (Exception e) { 331 } catch (Exception e) {
  332 + // TODO @haohao:可以有个 client id
339 log.error("[sendDataUpReply][发送数据上报回复失败]", e); 333 log.error("[sendDataUpReply][发送数据上报回复失败]", e);
340 } 334 }
341 } 335 }
@@ -352,12 +346,11 @@ public class IotTcpUpstreamHandler implements Handler&lt;NetSocket&gt; { @@ -352,12 +346,11 @@ public class IotTcpUpstreamHandler implements Handler&lt;NetSocket&gt; {
352 .addr(dataPackage.getAddr()) 346 .addr(dataPackage.getAddr())
353 .code(TcpDataPackage.CODE_EVENT_UP) 347 .code(TcpDataPackage.CODE_EVENT_UP)
354 .mid(dataPackage.getMid()) 348 .mid(dataPackage.getMid())
355 - .payload("0") // 0表示成功 349 + .payload("0") // 0 表示成功
356 .build(); 350 .build();
357 351
358 io.vertx.core.buffer.Buffer replyBuffer = TcpDataEncoder.encode(replyPackage); 352 io.vertx.core.buffer.Buffer replyBuffer = TcpDataEncoder.encode(replyPackage);
359 client.sendMessage(replyBuffer); 353 client.sendMessage(replyBuffer);
360 -  
361 } catch (Exception e) { 354 } catch (Exception e) {
362 log.error("[sendEventUpReply][发送事件上报回复失败]", e); 355 log.error("[sendEventUpReply][发送事件上报回复失败]", e);
363 } 356 }
@@ -385,7 +378,6 @@ public class IotTcpUpstreamHandler implements Handler&lt;NetSocket&gt; { @@ -385,7 +378,6 @@ public class IotTcpUpstreamHandler implements Handler&lt;NetSocket&gt; {
385 } 378 }
386 379
387 log.info("[handleConnectionClose][处理连接关闭完成] 设备地址: {}", deviceAddr); 380 log.info("[handleConnectionClose][处理连接关闭完成] 设备地址: {}", deviceAddr);
388 -  
389 } catch (Exception e) { 381 } catch (Exception e) {
390 log.error("[handleConnectionClose][处理连接关闭失败]", e); 382 log.error("[handleConnectionClose][处理连接关闭失败]", e);
391 } 383 }