Compare commits

3 Commits

4 changed files with 64 additions and 29 deletions

View File

@@ -211,7 +211,8 @@ services:
SPRING_DATA_REDIS_PASSWORD: "9kHXcZ1ojFsD" SPRING_DATA_REDIS_PASSWORD: "9kHXcZ1ojFsD"
ROCKETMQ_NAME_SERVER: 172.17.16.14:9876 ROCKETMQ_NAME_SERVER: 172.17.16.14:9876
# 添加这一行
VIEWSH_IOT_GATEWAY_RPC_URL: "http://aiot-iot-server:48091"
volumes: volumes:
- app-logs:/app/logs - app-logs:/app/logs
deploy: deploy:

View File

@@ -38,26 +38,23 @@ public class Jt808ProtocolUtil {
} }
try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) { try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
// 写入起始部分 // 只处理 start 到 end 范围内的数据(不包含 start 之前和 end 之后的数据)
for (int i = 0; i < start; i++) { // 这样返回的数组就是纯净的、去除了首尾标识符且已反转义的数据包
baos.write(bs[i]); for (int i = start; i < end; i++) {
} if (bs[i] == 0x7d && i + 1 < end) { // 确保 i+1 不越界
// 处理需要反转义的部分 if (bs[i + 1] == 0x01) {
for (int i = start; i < end - 1; i++) {
if (bs[i] == 0x7d && bs[i + 1] == 0x01) {
baos.write(0x7d); baos.write(0x7d);
i++; i++;
} else if (bs[i] == 0x7d && bs[i + 1] == 0x02) { } else if (bs[i + 1] == 0x02) {
baos.write(0x7e); baos.write(0x7e);
i++; i++;
} else { } else {
baos.write(bs[i]); baos.write(bs[i]);
} }
} } else {
// 写入结束部分
for (int i = end - 1; i < bs.length; i++) {
baos.write(bs[i]); baos.write(bs[i]);
} }
}
return baos.toByteArray(); return baos.toByteArray();
} }
} }

View File

@@ -142,10 +142,47 @@ public class IotTcpUpstreamHandler implements Handler<NetSocket> {
// 5. 判断是否为认证消息 // 5. 判断是否为认证消息
if (isAuthenticationMessage(message)) { if (isAuthenticationMessage(message)) {
handleAuthenticationWithProtocol(clientId, message, codecType, socket, handler); handleAuthenticationWithProtocol(clientId, message, codecType, socket, handler);
} else {
// 针对 JT808 协议的特殊处理如果是位置上报thing.property.post且包含身份信息手机号尝试自动注册
// 这可以解决设备重启后未注册就发送数据的问题,或者简化认证流程
if (CODEC_TYPE_JT808.equals(codecType)) {
tryAutoRegisterJt808(clientId, message, codecType, socket, handler);
} else { } else {
handleBusinessWithProtocol(clientId, message, codecType, socket, handler); handleBusinessWithProtocol(clientId, message, codecType, socket, handler);
} }
} }
}
/**
* 尝试自动注册 JT808 设备
* <p>
* JT808 协议中,消息头包含终端手机号。如果设备未认证但发送了有效数据,
* 我们可以尝试提取手机号并进行隐式认证,而不是直接断开连接。
*/
private void tryAutoRegisterJt808(String clientId, IotDeviceMessage message,
String codecType, NetSocket socket,
ProtocolHandler handler) {
// 如果已认证,直接处理业务
if (!connectionManager.isNotAuthenticated(socket)) {
handleBusinessWithProtocol(clientId, message, codecType, socket, handler);
return;
}
log.info("[tryAutoRegisterJt808][尝试自动认证 JT808 设备clientId: {}]", clientId);
// 使用认证逻辑处理JT808 协议处理器会提取手机号进行认证)
// 这里把业务消息当作认证消息处理,如果协议处理器支持从业务消息提取身份,就能成功
// 注意:这依赖于 Jt808ProtocolHandler 的 handleAuthentication 实现能够处理非注册消息
handleAuthenticationWithProtocol(clientId, message, codecType, socket, handler);
// 如果认证成功handleAuthenticationWithProtocol 内部会注册连接),则继续处理业务消息
if (!connectionManager.isNotAuthenticated(socket)) {
log.info("[tryAutoRegisterJt808][自动认证成功继续处理业务消息clientId: {}]", clientId);
handleBusinessWithProtocol(clientId, message, codecType, socket, handler);
} else {
// 认证依然失败,提示未认证(日志已在 handleAuthenticationWithProtocol 中打印)
}
}
/** /**
* 使用协议处理器处理认证消息 * 使用协议处理器处理认证消息

View File

@@ -36,13 +36,13 @@ viewsh:
gateway: gateway:
# 设备 RPC 配置 # 设备 RPC 配置
rpc: rpc:
url: ${IOT_RPC_URL:http://127.0.0.1:48091} url: ${VIEWSH_GATEWAY_RPC_URL:http://127.0.0.1:48091}
connect-timeout: ${IOT_RPC_CONNECT_TIMEOUT:30s} connect-timeout: ${VIEWSH_RPC_CONNECT_TIMEOUT:30s}
read-timeout: ${IOT_RPC_READ_TIMEOUT:30s} read-timeout: ${VIEWSH_RPC_READ_TIMEOUT:30s}
# 设备 Token 配置 # 设备 Token 配置
token: token:
secret: ${IOT_TOKEN_SECRET:viewshIotGatewayTokenSecret123456789} secret: ${VIEWSH_IOT_TOKEN_SECRET:viewshIotGatewayTokenSecret123456789}
expiration: ${IOT_TOKEN_EXPIRATION:7d} expiration: ${VIEWSH_IOT_TOKEN_EXPIRATION:7d}
# 协议配置 # 协议配置
protocol: protocol: