fix(iot): TCP消息处理容错改进,避免异常断开连接

- 消息格式无法识别时记录警告并跳过,不断开连接
- 消息解码失败时记录警告并跳过,不断开连接
- 设备不存在时断开连接,其他认证失败只记录日志
- 添加 bytesToHex 工具方法用于调试

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
lzh
2026-01-21 18:05:23 +08:00
parent 7c7b122de3
commit 5dab9622d6

View File

@@ -112,17 +112,30 @@ public class IotTcpUpstreamHandler implements Handler<NetSocket> {
// 2. 获取消息格式类型
String codecType = getMessageCodecType(buffer, socket);
if (codecType == null) {
// 无法识别消息格式,记录警告但不断开连接
byte[] data = buffer.getBytes();
String preview = bytesToHex(data, Math.min(32, data.length));
log.warn("[processMessage][无法识别消息格式跳过该消息clientId: {}, 数据前32字节: {}]",
clientId, preview);
return;
}
// 3. 解码消息
IotDeviceMessage message;
try {
message = deviceMessageService.decodeDeviceMessage(buffer.getBytes(), codecType);
if (message == null) {
throw new Exception("解码后消息为空");
// 解码失败(如消息格式错误),记录警告但不断开连接
log.warn("[processMessage][消息解码失败跳过该消息clientId: {}, codecType: {}]",
clientId, codecType);
return;
}
} catch (Exception e) {
// 消息格式错误时抛出异常,由上层处理连接断开
throw new Exception("消息解码失败: " + e.getMessage(), e);
// 其他异常也记录警告但不断开连接
log.warn("[processMessage][消息解码异常跳过该消息clientId: {}, codecType: {}, 错误: {}]",
clientId, codecType, e.getMessage());
return;
}
// 4. 查找协议处理器
@@ -147,7 +160,7 @@ public class IotTcpUpstreamHandler implements Handler<NetSocket> {
* 认证结果处理:
* - SUCCESS注册连接发送上线消息
* - PENDING等待后续认证步骤如 JT808 注册后等待鉴权)
* - FAILURE认证失败不做处理(协议处理器已发送失败响应)
* - FAILURE认证失败如果设备不存在则断开连接,否则只记录日志
*
* @param clientId 客户端 ID
* @param message 认证消息
@@ -178,9 +191,16 @@ public class IotTcpUpstreamHandler implements Handler<NetSocket> {
handler.getProtocolType(), result.getMessage());
} else {
// 认证失败:协议处理器已发送失败响应,这里只记录日志
// 认证失败
String failureReason = result.getMessage();
log.warn("[handleAuthentication][认证失败clientId: {}, 协议: {}, 原因: {}]",
clientId, handler.getProtocolType(), result.getMessage());
clientId, handler.getProtocolType(), failureReason);
// 如果设备不存在,断开连接
if (failureReason != null && failureReason.contains("设备不存在")) {
log.warn("[handleAuthentication][设备不存在断开连接clientId: {}]", clientId);
socket.close();
}
}
} catch (Exception e) {
@@ -373,7 +393,7 @@ public class IotTcpUpstreamHandler implements Handler<NetSocket> {
*/
private void cleanupConnection(NetSocket socket) {
try {
// 1. 发送离线消息(如果认证)
// 1. 发送离线消息(如果<EFBFBD><EFBFBD><EFBFBD>认证)
IotTcpConnectionManager.ConnectionInfo connectionInfo = connectionManager.getConnectionInfo(socket);
if (connectionInfo != null && connectionInfo.isAuthenticated()) {
IotDeviceMessage offlineMessage = IotDeviceMessage.buildStateOffline();
@@ -391,4 +411,26 @@ public class IotTcpUpstreamHandler implements Handler<NetSocket> {
}
}
/**
* 字节数组转十六进制字符串
*
* @param bytes 字节数组
* @param limit 最大长度
* @return 十六进制字符串
*/
private String bytesToHex(byte[] bytes, int limit) {
if (bytes == null || bytes.length == 0) {
return "";
}
int length = Math.min(bytes.length, limit);
StringBuilder sb = new StringBuilder(length * 2);
for (int i = 0; i < length; i++) {
sb.append(String.format("%02X", bytes[i]));
}
if (bytes.length > limit) {
sb.append("...");
}
return sb.toString();
}
}