聊聊MQTT协议,实战分享(附源码)

简介

MQTT 可以被解释为一种低开销,低带宽占用的即时通讯协议,可以用较少的代码和带宽为远程设备连接提供实时可靠的消息服务,它适用于硬件性能低下的远程设备以及网络状况糟糕的环境下,因此 MQTT 协议在 IoT(Internet of things,物联网),小型设备应用,移动应用等方面有较广泛的应用。

优点:代码量少,开销低,带宽占用小,即时通讯协议。

MQTT原理

实现mqtt协议需要客户端和服务器端通讯完成,在通讯中,mqtt协议中有三种身份:发布者(publish),代理(broker)(服务器),订阅者(subscribe)。其中,消息的发布者和订阅者都是客户端。消息代理是服务器,消息发布者可以同时是订阅者,传输过程如下如所示。

有别于传统的客户端/服务器通讯协议,MQTT协议并不是端到端的,消息传递通过代理,包括会话(session)也不是建立在发布者和订阅者之间,而是建立在端和代理之间。代理解除了发布者和订阅者之间的耦合。

除了发布者和订阅者之间传递普通消息,代理还可以为发布者处理保留消息和遗愿消息,并可以更改服务质量(QoS)等级。

MQTT主题

1、主题层级分隔符"/"

用于分割主题的每个层级,为主题名提供一个分层结构。如主题:

bash 复制代码
china/anhui
china/anhui/hefei

2、多层通配符"#"

用于匹配主题中任意层级的通配符。如主题:china/#

bash 复制代码
china/anhui
china/anhui/hefei
china/anhui/hefei/shushan

3、单层通配符"+"

加号是只能用于单个主题层级匹配的通配符。如主题:

bash 复制代码
china/+      只能匹配 china/anhui
china/+/+/shushan     能匹配china/anhui/hefei/shushan

4、通配符"$"

通配符"$"表示匹配一个字符,只要不是放在主题的最开头,即:

bash 复制代码
$xx
/$xx
/xx$

实战应用

对接协议部分内容

SpringBoot集成Mqtt协议

本篇文章就不重点介绍MQTT相关的内容了,主要学会怎么运用到实际开发工作中。

  1. 添加依赖
xml 复制代码
<dependency>
   <groupId>org.springframework.integration</groupId>
   <artifactId>spring-integration-mqtt</artifactId>
</dependency>
  1. 添加配置类
java 复制代码
@Configuration
@ConfigurationProperties(prefix="spring.mqtt")
public class MqttProperties {
    private String url;
    private String username;
    private String password;
    private String clientId;

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getClientId() {
        return clientId;
    }

    public void setClientId(String clientId) {
        this.clientId = clientId;
    }
}
java 复制代码
@Configuration
@ConditionalOnBean(MqttProperties.class)
public class MqttConfiguration {

    @Autowired
    private MqttProperties mqttProperties;

    @Autowired
    private MqttMessageHandler mqttMessageHandler;

    /**
     * 创建MqttPahoClientFactory,设置MQTT Broker连接属性,如果使用SSL验证,也在这里设置。
     *
     * @return factory
     */
    @Bean
    public MqttPahoClientFactory mqttClientFactory() {
        DefaultMqttPahoClientFactory factory = new DefaultMqttPahoClientFactory();
        MqttConnectOptions options = new MqttConnectOptions();

        // 设置代理端的URL地址,可以是多个
        options.setServerURIs(new String[]{mqttProperties.getUrl()});
        options.setUserName(mqttProperties.getUsername());
        options.setPassword(mqttProperties.getPassword().toCharArray());
        options.setKeepAliveInterval(120);
        factory.setConnectionOptions(options);
        return factory;
    }

    /**
     * 入站通道
     */
    @Bean
    public MessageChannel mqttInputChannel() {
        return new DirectChannel();
    }

    /**
     * 入站
     */
    @Bean
    public MessageProducer inbound() {
        // Paho客户端消息驱动通道适配器,主要用来订阅主题
        MqttPahoMessageDrivenChannelAdapter adapter = new MqttPahoMessageDrivenChannelAdapter(
                mqttProperties.getClientId() + "-consumer",
                mqttClientFactory(),
                MqttConstants.UP_DEVICE_STATE,
                MqttConstants.UP_DEVICE_STATUS,
                MqttConstants.UP_DEVICE_EVENT,
                MqttConstants.UP_DEVICE_SET_ACK,
                MqttConstants.UP_DEVICE_GET_ACK,
                MqttConstants.UP_DEVICE_CAPTURE_REPORT,
                MqttConstants.UP_DEVICE_CONTROL_QUERY_ACK,
                MqttConstants.UP_DEVICE_CONTROL_ACK);
        // Paho消息转换器
        DefaultPahoMessageConverter defaultPahoMessageConverter = new DefaultPahoMessageConverter();
        adapter.setConverter(defaultPahoMessageConverter);
        adapter.setCompletionTimeout(5000);
        // 设置QoS
        adapter.setQos(1);
        adapter.setOutputChannel(mqttInputChannel());
        return adapter;
    }

    /**
     * ServiceActivator注解表明:当前方法用于处理MQTT消息,inputChannel参数指定了用于消费消息的channel。
     *
     * @return
     */
    @Bean
    @ServiceActivator(inputChannel = "mqttInputChannel")
    public MessageHandler handler() {
        return mqttMessageHandler;
    }

    /**
     * 出站通道
     */
    @Bean
    public MessageChannel mqttOutboundChannel() {
        return new DirectChannel();
    }

    /**
     * 出站
     */
    @Bean
    @ServiceActivator(inputChannel = "mqttOutboundChannel")
    public MessageHandler outbound() {
        // 发送消息和消费消息Channel可以使用相同MqttPahoClientFactory
        MqttPahoMessageHandler mqttPahoMessageHandler = new MqttPahoMessageHandler(
                mqttProperties.getClientId() + "-producer", mqttClientFactory());
        // 如果设置成true,即异步,发送消息时将不会阻塞。
        mqttPahoMessageHandler.setAsync(true);
        // 设置默认QoS
        mqttPahoMessageHandler.setDefaultQos(1);
        // Paho消息转换器
        DefaultPahoMessageConverter defaultPahoMessageConverter = new DefaultPahoMessageConverter();
        mqttPahoMessageHandler.setConverter(defaultPahoMessageConverter);
        return mqttPahoMessageHandler;
    }
}
  1. 消息处理类
java 复制代码
@Service
public class MqttMessageHandler implements MessageHandler {

    private final Logger logger = LoggerFactory.getLogger(MqttMessageHandler.class);

    @Override
    public void handleMessage(Message<?> message) throws MessagingException {
        try {
            String payload = message.getPayload().toString();
            String topic = message.getHeaders().get("mqtt_receivedTopic").toString();
            logger.info("接受来自mqtt的订阅信息,topic:{}", topic);
            //离线上报
            if (topic.matches(".+/offline")) {
                statusReport(payload);
            }
            //状态上报
            else if (topic.matches(".+/status")) {
                deviceInfoReport(payload);
            } 
            //事件上报
            else if (topic.matches(".+/eventReport")) {
                eventReport(payload);
            } else {
                logger.info("主题topic:{},负载payload:{}", topic, payload);
            }
        } catch (Exception e) {
            logger.error("handleMessage 接受mqtt订阅消息异常:", e);
        }
    }
    
      /**
     * 设备状态上报
     *
     * @param payload
     */
    private void statusReport(String payload) {
        OfflineReport offlineReport = JSONUtil.toBean(payload, OfflineReport.class);
        logger.info("收到设备状态信息上报:{}", offlineReport);
        //...省略
    }

 //...省略
   
}
java 复制代码
/**
 * 消息发送
 */
@MessagingGateway(defaultRequestChannel = "mqttOutboundChannel")
public interface MqttGateway {

    /**
     * 定义重载方法,用于消息发送
     *
     * @param payload
     */
    void sendToMqtt(String payload);

    /**
     * 指定topic进行消息发送
     *
     * @param topic
     * @param payload
     */
    void sendToMqtt(@Header(MqttHeaders.TOPIC) String topic, String payload);

    void sendToMqtt(@Header(MqttHeaders.TOPIC) String topic, @Header(MqttHeaders.QOS) int qos, String payload);

    void sendToMqtt(@Header(MqttHeaders.TOPIC) String topic, @Header(MqttHeaders.QOS) int qos, byte[] payload);
}

源码地址:gitee.com/jiangwang00...

小结

本文简单介绍了一下MQTT协议的基本知识,在实际工作中,MQTT通常应用于物联网、智能家居等设备和应用程序之间的通信。在嵌入式领域,MQTT已经占据着无法替代的分量,因为大多数的嵌入式设备,都需要这样的协议进行数据交互。

2024一起加油~

相关推荐
小黄编程快乐屋1 小时前
各个排序算法基础速通万字介绍
java·算法·排序算法
kingwebo'sZone1 小时前
ASP.net WebAPI 上传图片实例(保存显示随机文件名)
后端·asp.net
桑榆肖物1 小时前
一个简单的ASP.NET 一致性返回工具库
后端·asp.net
材料苦逼不会梦到计算机白富美3 小时前
贪心算法-区间问题 C++
java·c++·贪心算法
组态软件4 小时前
web组态软件
前端·后端·物联网·编辑器·html
Peter_chq4 小时前
【计算机网络】多路转接之select
linux·c语言·开发语言·网络·c++·后端·select
小小李程序员7 小时前
LRU缓存
java·spring·缓存
cnsxjean7 小时前
SpringBoot集成Minio实现上传凭证、分片上传、秒传和断点续传
java·前端·spring boot·分布式·后端·中间件·架构
hadage2337 小时前
--- stream 数据流 java ---
java·开发语言
《源码好优多》7 小时前
基于Java Springboot汽配销售管理系统
java·开发语言·spring boot