<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Mqtt on LeafCxy's Blog</title><link>https://leafcxy.github.io/tags/mqtt/</link><description>Recent content in Mqtt on LeafCxy's Blog</description><generator>Hugo</generator><language>zh-cn</language><lastBuildDate>Tue, 26 Aug 2025 00:51:43 +0000</lastBuildDate><atom:link href="https://leafcxy.github.io/tags/mqtt/index.xml" rel="self" type="application/rss+xml"/><item><title>mqtt中的retained是什么意思</title><link>https://leafcxy.github.io/posts/2025-08-26/</link><pubDate>Tue, 26 Aug 2025 00:51:43 +0000</pubDate><guid>https://leafcxy.github.io/posts/2025-08-26/</guid><description>&lt;p&gt;MQTT 中的 &lt;code&gt;retained&lt;/code&gt;（保留消息）是一个重要概念，主要作用如下：&lt;/p&gt;
&lt;h2 id="基本定义"&gt;基本定义&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;retained&lt;/code&gt; 是 MQTT 消息的一个标志位，当发布者发送消息时可以设置 &lt;code&gt;RETAIN&lt;/code&gt; 标志为 true，这样的消息会被 MQTT 代理（broker）保存。&lt;/p&gt;
&lt;h2 id="主要特性"&gt;主要特性&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;消息持久化&lt;/strong&gt;：Broker 会为每个主题保存最后一条带有 retain 标志的消息&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;新订阅者立即获取&lt;/strong&gt;：当新的客户端订阅某个主题时，会立即收到该主题的最后一条保留消息&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;自动更新&lt;/strong&gt;：当有新的保留消息发布到同一主题时，旧的保留消息会被替换&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;清除机制&lt;/strong&gt;：发布一条空内容（payload 为空）的保留消息可以清除该主题的保留消息&lt;/li&gt;
&lt;/ul&gt;
&lt;!-- more --&gt;
&lt;h2 id="使用场景"&gt;使用场景&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;设备状态报告&lt;/strong&gt;：传感器发布温度、湿度等状态信息&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;配置信息&lt;/strong&gt;：系统配置参数的发布&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;在线状态&lt;/strong&gt;：设备的上下线状态通知&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;初始数据&lt;/strong&gt;：确保新订阅者能立即获得最新数据&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="工作示例"&gt;工作示例&lt;/h2&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;# 客户端A发布保留消息
PUBLISH topic:&amp;#34;home/temperature&amp;#34; payload:&amp;#34;25.6&amp;#34; retain:true
# 客户端B稍后订阅该主题
SUBSCRIBE topic:&amp;#34;home/temperature&amp;#34;
# 客户端B会立即收到之前发布的保留消息
MESSAGE topic:&amp;#34;home/temperature&amp;#34; payload:&amp;#34;25.6&amp;#34; retain:true
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;保留消息机制使得 MQTT 非常适合物联网场景，新设备上线时能立即获取到最新的状态信息，而不需要等待下一次数据更新。&lt;/p&gt;</description></item><item><title>关于MQTT</title><link>https://leafcxy.github.io/posts/2025-07-23-1/</link><pubDate>Wed, 23 Jul 2025 01:34:09 +0000</pubDate><guid>https://leafcxy.github.io/posts/2025-07-23-1/</guid><description>&lt;p&gt;MQTT（Message Queuing Telemetry Transport，消息队列遥测传输协议），是一种基于发布/订阅（publish/subscribe）模式的&amp;quot;轻量级&amp;quot;通讯协议，该协议构建于TCP/IP协议上，由IBM在1999年发布。MQTT最大优点在于，可以以极少的代码和有限的带宽，为连接远程设备提供实时可靠的消息服务。作为一种低开销、低带宽占用的即时通讯协议，使其在物联网、小型设备、移动应用等方面有较广泛的应用。&lt;/p&gt;
&lt;!-- more --&gt;
&lt;p&gt;MQTT是一个基于客户端-服务器的消息发布/订阅传输协议。MQTT协议是轻量、简单、开放和易于实现的，这些特点使它适用范围非常广泛。在很多情况下，包括受限的环境中，如：机器与机器（M2M）通信和物联网（IoT）。其在，通过卫星链路通信传感器、偶尔拨号的医疗设备、智能家居、及一些小型化设备中已广泛使用。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-csharp" data-lang="csharp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;using&lt;/span&gt; MQTTnet;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;using&lt;/span&gt; MQTTnet.Client;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;async&lt;/span&gt; Task Handle_Received_Application_Message()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; mqttFactory = &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; MqttFactory();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;using&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; mqttClient = mqttFactory.CreateMqttClient())
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; mqttClientOptions = &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; MqttClientOptionsBuilder()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .WithTcpServer(&lt;span style="color:#e6db74"&gt;&amp;#34;192.168.106.76&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .Build();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; mqttClient.ApplicationMessageReceivedAsync += e =&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;string&lt;/span&gt; payload = Encoding.UTF8.GetString(e.ApplicationMessage.Payload);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; HandlePayload(payload);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; Task.CompletedTask;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; };
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; mqttSubscribeOptions = mqttFactory.CreateSubscribeOptionsBuilder()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .WithTopicFilter(f =&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; f.WithTopic(&lt;span style="color:#e6db74"&gt;&amp;#34;fe-prod/sso2_burnin/v1/0c:b2:b7:ce:de:73/SSO2/all-data&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; })
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .WithTopicFilter(f =&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; f.WithTopic(&lt;span style="color:#e6db74"&gt;&amp;#34;fe-prod/sso2_burnin/v1/fc:69:47:b8:3a:54/SSO2/all-data&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; })
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .WithTopicFilter(f =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; f.WithTopic(&lt;span style="color:#e6db74"&gt;&amp;#34;fe-prod/sso2_burnin/v1/24:76:25:e9:9b:73/SSO2/all-data&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; })
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .Build();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; mqttClient.DisconnectedAsync += &lt;span style="color:#66d9ef"&gt;async&lt;/span&gt; e =&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; AddLog(&lt;span style="color:#e6db74"&gt;&amp;#34;Disconnected...&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;await&lt;/span&gt; Task.Delay(&lt;span style="color:#ae81ff"&gt;1000&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; log.Error(&lt;span style="color:#e6db74"&gt;&amp;#34;连接已断开,尝试重新连接...&amp;#34;&lt;/span&gt;, e.Exception);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; i = &lt;span style="color:#ae81ff"&gt;9&lt;/span&gt;; i &amp;gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;; i--)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; AddLog(&lt;span style="color:#e6db74"&gt;$&amp;#34;Reconnect after {i}s...&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;await&lt;/span&gt; Task.Delay(&lt;span style="color:#ae81ff"&gt;1000&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;await&lt;/span&gt; mqttClient.ConnectAsync(mqttClientOptions, CancellationToken.None);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;await&lt;/span&gt; mqttClient.SubscribeAsync(mqttSubscribeOptions, CancellationToken.None);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;//if (e.ClientWasConnected)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;//{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// // Use the current options as the new options.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// await mqttClient.ConnectAsync(mqttClient.Options);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;//}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;//else&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;//{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// await mqttClient.ConnectAsync(mqttClientOptions, CancellationToken.None);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// await mqttClient.SubscribeAsync(mqttSubscribeOptions, CancellationToken.None);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;//}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; };
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;await&lt;/span&gt; mqttClient.ConnectAsync(mqttClientOptions, CancellationToken.None);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;await&lt;/span&gt; mqttClient.SubscribeAsync(mqttSubscribeOptions, CancellationToken.None);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; locks.WaitOne();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; paho.mqtt.client &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; mqtt
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Successful Connection Callback&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;on_connect&lt;/span&gt;(client, userdata, flags, rc):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; print(&lt;span style="color:#e6db74"&gt;&amp;#39;Connected with result code &amp;#39;&lt;/span&gt;&lt;span style="color:#f92672"&gt;+&lt;/span&gt;str(rc))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; client&lt;span style="color:#f92672"&gt;.&lt;/span&gt;subscribe(&lt;span style="color:#e6db74"&gt;&amp;#39;testtopic/#&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Message delivery callback&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;on_message&lt;/span&gt;(client, userdata, msg):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; print(msg&lt;span style="color:#f92672"&gt;.&lt;/span&gt;topic&lt;span style="color:#f92672"&gt;+&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34; &amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;+&lt;/span&gt;str(msg&lt;span style="color:#f92672"&gt;.&lt;/span&gt;payload))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;client &lt;span style="color:#f92672"&gt;=&lt;/span&gt; mqtt&lt;span style="color:#f92672"&gt;.&lt;/span&gt;Client()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Set callback handler&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;client&lt;span style="color:#f92672"&gt;.&lt;/span&gt;on_connect &lt;span style="color:#f92672"&gt;=&lt;/span&gt; on_connect
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;client&lt;span style="color:#f92672"&gt;.&lt;/span&gt;on_message &lt;span style="color:#f92672"&gt;=&lt;/span&gt; on_message
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Set up connection&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;client&lt;span style="color:#f92672"&gt;.&lt;/span&gt;connect(&lt;span style="color:#e6db74"&gt;&amp;#39;broker.emqx.io&amp;#39;&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;1883&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;60&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Publish message&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;client&lt;span style="color:#f92672"&gt;.&lt;/span&gt;publish(&lt;span style="color:#e6db74"&gt;&amp;#39;emqtt&amp;#39;&lt;/span&gt;,payload&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;Hello World&amp;#39;&lt;/span&gt;,qos&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;client&lt;span style="color:#f92672"&gt;.&lt;/span&gt;loop_forever()
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description></item></channel></rss>