项目场景:

有个需求是这样的,需要对自研设备的程序中的文件进行操作,例如查看文件列表、下载文件、上传文件等操作。有点类似于我们在linux系统中的操作,例如ls、rz、sz这些操作。
具体的通讯情况是这样
前端-----后端:http
后端-----设备:mqtt
条件:

  1. 允许超时报错。即命令请求后超过一定时间设备没有回复即表示通讯失败,返回超时。
  2. 设备回复消息后,应立即显示在前端页面上。

问题描述

  1. 开始我的想法是这样的,由于后台跟设备的通讯通过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; // 超时未获取到结果
    }
Logo

北京人形旗下天工造物具身智能开源社区,聚焦具身天工与慧思开物两大平台

更多推荐