通过http接口调用与设备进行mqtt通讯
·
项目场景:
有个需求是这样的,需要对自研设备的程序中的文件进行操作,例如查看文件列表、下载文件、上传文件等操作。有点类似于我们在linux系统中的操作,例如ls、rz、sz这些操作。
具体的通讯情况是这样
前端-----后端:http
后端-----设备:mqtt
条件:
- 允许超时报错。即命令请求后超过一定时间设备没有回复即表示通讯失败,返回超时。
- 设备回复消息后,应立即显示在前端页面上。
问题描述
- 开始我的想法是这样的,由于后台跟设备的通讯通过mqtt这种发布订阅模式的情况,是异步的,就不是像http那种阻塞式一问一答的情况。
我想着前端处理的情况可以是:
1.1.提供两个接口给前端,一个接口负责下发指令给设备,另外一个接口返回结果,让前端轮询获取,轮询几次没有获得的话就返回失败
1.2.前端直连emqx,直接发送指令,并订阅。
1.3.使用websocket建立长连接,通过等待后台给结果实时推送。
原因分析:
排除了1.2和1.3,打算采取1.1
1.2:考虑到前端直连不安全,而且可能涉及证书之类的无法兼容问题,同时无法实现准确的超时机制。因此排除
1.3:考虑到做超时失败比较不太好处理,因为不能一直等待,有可能设备会离线。
最终:使用1.1过程中发现可优化点:可以把等待这个逻辑交给后端做,前端不需要做那么复杂的逻辑,而且大大降低了频繁请求http带来的性能损耗。
- 后端只需要等待、查询redis
- 如果查询到了,即返回结果
- 如果查询不到,等待数秒,继续查询,直到达到最大等待时间,返回超时。
解决方案:
1、先发送mqtt报文给设备,让其响应并返回
2、再执行等待轮询的处理
这个逻辑适合大部分物联网的
设备远程控制
// 1、使用直接MQTT消息发送
sendDirectMqttMessage(device, "listFile", params, messageId);
// 2、等待设备回复
String result = emsFileResultService.waitForFileOperationResult(messageId, "list", 30);
/**
* 等待文件操作结果
*/
public String waitForFileOperationResult(String messageId, String operationType, int timeoutSeconds) {
String key = RedisKeyConstants.EMS_FILE_REPLY_PREFIX + operationType + ":" + messageId;
// 轮询等待结果,最多等待指定时间
long startTime = System.currentTimeMillis();
while (System.currentTimeMillis() - startTime < timeoutSeconds * 1000) {
String result = stringRedisTemplate.opsForValue().get(key);
if (result != null) {
// 获取到结果后删除Redis中的缓存
stringRedisTemplate.delete(key);
return result;
}
try {
Thread.sleep(500); // 每500ms检查一次
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
break;
}
}
return null; // 超时未获取到结果
}
更多推荐
所有评论(0)