164 lines
4.7 KiB
Markdown
164 lines
4.7 KiB
Markdown
# 上电触发响应处理优化说明
|
||
|
||
## 优化目标
|
||
|
||
在上电触发场景下,**在协议解码之前拦截设备回复**,直接匹配到等待的`requestR()`调用,避免走完整的协议解码和MQ流程,减少通信负担,提高响应速度。
|
||
|
||
## 实现方案
|
||
|
||
### 1. 新增Handler:PowerOnTriggerResponseHandler
|
||
|
||
**位置:** `fastbee-server/iot-server-core/src/main/java/com/fastbee/server/handler/PowerOnTriggerResponseHandler.java`
|
||
|
||
**功能:**
|
||
- 在协议解码之前拦截设备回复的原始ByteBuf数据
|
||
- 创建简单的Message对象(不解析内容)
|
||
- 调用`Session.response()`尝试匹配到等待的`requestR()`调用
|
||
- 如果匹配成功,`requestR()`会立即返回,无需等待协议解码
|
||
|
||
### 2. Handler链顺序
|
||
|
||
```
|
||
TCPMessageAdapter (接收原始ByteBuf)
|
||
↓
|
||
PowerOnTriggerResponseHandler (拦截并匹配响应) ← 新增
|
||
↓
|
||
MessageDecoderWrapper (协议解码)
|
||
↓
|
||
DispatcherHandler (消息分发)
|
||
```
|
||
|
||
### 3. 工作原理
|
||
|
||
```
|
||
1. 平台下发指令
|
||
PowerOnTriggerTaskExecutor.execute()
|
||
→ MessageManager.requestR()
|
||
→ Session.request() 订阅等待响应
|
||
|
||
2. 设备回复原始字节数据
|
||
设备发送:ByteBuf (例如:7E 01 03 00 00 00 02 C4 0B 7E)
|
||
|
||
3. PowerOnTriggerResponseHandler拦截
|
||
- 接收原始ByteBuf
|
||
- 创建简单的Message对象(不解析内容)
|
||
- 调用Session.response()尝试匹配
|
||
|
||
4. 匹配成功
|
||
- Session.response()找到等待的request
|
||
- 立即唤醒等待的Mono
|
||
- requestR()返回成功(code=200, data=Message对象)
|
||
- PowerOnTriggerTaskExecutor收到响应,更新任务状态
|
||
|
||
5. 继续传递(可选)
|
||
- 如果继续传递,协议解码也会处理(但上电触发任务已完成)
|
||
- 如果不想走协议解码,可以注释掉ctx.fireChannelRead(msg)
|
||
```
|
||
|
||
## 优势
|
||
|
||
1. **减少通信负担**
|
||
- 不需要走完整的协议解码流程
|
||
- 不需要发送到MQ异步处理
|
||
- 直接同步匹配,响应更快
|
||
|
||
2. **提高精准度**
|
||
- 直接匹配等待的request,不依赖协议特征识别
|
||
- 避免协议解码误判导致的问题
|
||
|
||
3. **降低延迟**
|
||
- 200ms内设备回复,立即匹配成功
|
||
- 无需等待协议解码和MQ处理
|
||
|
||
## 代码修改
|
||
|
||
### 1. PowerOnTriggerResponseHandler.java
|
||
|
||
```java
|
||
@Override
|
||
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
|
||
Packet packet = (Packet) msg;
|
||
Session session = packet.session;
|
||
ByteBuf byteBuf = packet.byteBuf;
|
||
|
||
// 创建简单的Message对象,只用于匹配响应
|
||
Message responseMessage = new Message();
|
||
responseMessage.setClientId(session.getClientId());
|
||
responseMessage.setPayload(byteBuf.retain());
|
||
|
||
// 尝试匹配到等待的request
|
||
boolean matched = session.response(responseMessage);
|
||
|
||
if (matched) {
|
||
log.debug("=>上电触发-设备回复已匹配,设备编号:{}", session.getClientId());
|
||
// 匹配成功,继续传递(可选)
|
||
ctx.fireChannelRead(msg);
|
||
} else {
|
||
// 没有匹配到,继续正常流程
|
||
responseMessage.getPayload().release();
|
||
ctx.fireChannelRead(msg);
|
||
}
|
||
}
|
||
```
|
||
|
||
### 2. TCPServer.java
|
||
|
||
```java
|
||
channel.pipeline()
|
||
.addLast(FastBeeConstant.SERVER.ADAPTER, adapter)
|
||
.addLast("powerOnTriggerHandler", powerOnTriggerHandler) // 新增
|
||
.addLast(FastBeeConstant.SERVER.DECODER, decoder)
|
||
// ...
|
||
```
|
||
|
||
## 使用说明
|
||
|
||
### 当前实现
|
||
|
||
- **匹配成功**:`requestR()`立即返回,`PowerOnTriggerTaskExecutor`收到响应
|
||
- **继续传递**:消息继续传递给协议解码器(可选,如果不想走协议解码可以注释掉)
|
||
|
||
### 如果不想走协议解码
|
||
|
||
如果完全不想走协议解码,可以修改`PowerOnTriggerResponseHandler`:
|
||
|
||
```java
|
||
if (matched) {
|
||
log.debug("=>上电触发-设备回复已匹配,设备编号:{}", session.getClientId());
|
||
// 匹配成功,直接消费掉,不走协议解码
|
||
byteBuf.release(); // 释放ByteBuf
|
||
return; // 不继续传递
|
||
}
|
||
```
|
||
|
||
### 注意事项
|
||
|
||
1. **ByteBuf引用计数**
|
||
- 使用`byteBuf.retain()`增加引用计数
|
||
- 如果匹配失败,需要`release()`释放
|
||
- 如果匹配成功,后续处理器会负责释放
|
||
|
||
2. **兼容性**
|
||
- 如果匹配失败,继续走正常流程(协议解码等)
|
||
- 不影响其他功能
|
||
|
||
3. **性能**
|
||
- 只在上电触发场景下生效
|
||
- 其他场景继续走正常流程
|
||
|
||
## 测试建议
|
||
|
||
1. **验证匹配成功**
|
||
- 下发上电触发指令
|
||
- 设备回复后,检查`requestR()`是否立即返回
|
||
- 检查`PowerOnTriggerTaskExecutor`是否正确更新任务状态
|
||
|
||
2. **验证性能**
|
||
- 对比优化前后的响应时间
|
||
- 检查是否减少了MQ消息量
|
||
|
||
3. **验证兼容性**
|
||
- 确保其他功能不受影响
|
||
- 确保协议解码仍然正常工作
|
||
|