MQTT同步通信实现

建议先阅读文末参考文章再回看本文实现

mqtt是发布订阅机制,消息发送方无法立即知道消息订阅方的返回消息。在一些场景下比如我通过mqtt给某温度传感器下发命令读取该设备的温度数据这时需要同步得到温度传感器返回的数据,这就需要把异步请求转化为同步请求。

下面参考https://www.cnblogs.com/goodAndyxublog/p/12393723.html所描述mq方案来实现。

1.方案整体流程

 1.发送mqtt消息生成DefaultFuture,等待返回消息。DefaultFuture的实现原理即为dubbo中DefaultFuture实现。DefaultFuture是本方案的核心


@RestController
@RequestMapping("mqtt")
public class TestController {
   @Autowired
   SynMqttSender synMqttSender;
    @PostMapping("send")
    public Message sendMsg(@RequestBody  Message message){
        DefaultFuture future = synMqttSender.sendMessage(message);
        return future.get();
    }
}

2 mqtt返回消息处理程序

  /**
     * MQTT消息处理器(消费者)
     */
    @Bean
    @ServiceActivator(inputChannel = CHANNEL_NAME_IN)
    public MessageHandler handler() {
        return new MessageHandler() {
            @Override
            public void handleMessage(Message<?> message) throws MessagingException {
                String topic = message.getHeaders().get("mqtt_receivedTopic").toString();

                if(topic.equals(Constant.MQTT_TOPIC_RES)){
                    String msg = message.getPayload().toString();
                    mqttResHandler.deal(JSONUtil.toBean(msg,com.ffy.mqtt.model.Message.class));
                }
                String msg = message.getPayload().toString();
                log.info("\n--------------------START-------------------\n" +
                        "接收到订阅消息:\ntopic:" + topic + "\nmessage:" + msg +
                        "\n---------------------END--------------------");
            }
        };
    }
@Component
public class MqttResHandler {


    public void deal(Message msg){
        //根据messageId判断是否是本机发送的消息
        Long msgId = msg.getMessageId();
        if(DefaultFuture.contains(msgId)){
            DefaultFuture.received(msg);
        }
    }
}

在参考文章中当接收到的异步返回的消息后通过mq广播给了所有机器进行处理,本场景中各服务订阅topic本身就能保证返回的消息被所有机器接收到。

实现要点在于DefeaultFuture的实现,参考文章已有详细说明。

2.最终效果演示

1.发送消息

2.为message生成一个唯一的messageId通过mqtt发送给订阅方。用mqtt.x模拟温度传感器订阅消息 

 3.返回响应消息带上接收到的messageId

 

 4 根据messageId找到唤醒等待的DefaultFuture返回数据

 本文采用rabbitmq作为mqtt-broker 

完整代码:https://github.com/setadd/mqtt

参考资料:

sprignboot集成mqtt

架构设计|异步请求如何同步处理?

Dubbo源码分析(十)同步调用与异步调用

源码分析Dubbo异步调用与事件回调机制

### 实现MQTT协议的同步通信 为了实现在Java中通过MQTT协议进行同步通信,可以采用Paho MQTT客户端库。该库提供了简单易用的方法来连接到MQTT代理并发送/接收消息。 #### 创建MQTT客户端实例 首先需要创建一个`MqttClient`对象表示与特定服务器建立的会话: ```java import org.eclipse.paho.client.mqttv3.MqttCallback; import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken; import org.eclipse.paho.client.mqttv3.MqttMessage; import org.eclipse.paho.client.mqttv3.MqttException; public class MqttSyncExample { private static final String BROKER_URL = "tcp://broker.hivemq.com:1883"; public void connect() throws MqttException { IMqttClient client = new MqttClient(BROKER_URL, MqttClient.generateClientId()); try { client.connect(); // 进一步操作... client.disconnect(); } finally { if (client != null && client.isConnected()) { client.disconnect(); } } } } ``` #### 发布消息 当调用`publish()`方法时,默认情况下它将以异步方式执行。如果希望阻塞直到确认收到,则可以通过设置QoS级别为至少一次(At Least Once),即数值1,并等待完成回调通知[^1]。 ```java // 设置发布选项 MqttMessage message = new MqttMessage("Hello".getBytes()); message.setQos(1); // 至少传递一次 IMqttDeliveryToken token = client.publish(topicName, message); token.waitForCompletion(); // 阻塞线程直至消息被确认 ``` #### 订阅主题并处理接收到的消息 订阅某个话题后,每当有新数据到达时都会触发注册过的监听器函数。为了让程序能够以同步的方式读取消息,在这里建议使用自定义回调类配合条件变量或信号量机制实现同步效果[^2]。 ```java class SyncListener implements MqttCallback { private Semaphore semaphore = new Semaphore(0); @Override public void messageArrived(String topic, MqttMessage message) throws Exception { System.out.println("Received Message:" + new String(message.getPayload())); semaphore.release(); // 唤醒等待中的线程 } public void waitForNextMessage(long timeoutMillis) throws InterruptedException { semaphore.tryAcquire(timeoutMillis, TimeUnit.MILLISECONDS); } } ... SyncListener listener = new SyncListener(); client.setCallback(listener); client.subscribe("/test/topic"); listener.waitForNextMessage(5000L); // 等待最多五秒获取下一条消息 ```
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值