MQTT 3.1.1 Clean Session连接断开后行为不符合预期
问题分析与解决方案
核心问题:测试场景不符合预期
你在测试中错误断开了发布者机器的以太网,但订阅者与Broker在同一机器,通过本地回环接口(127.0.0.1)通信,物理以太网断开不会影响本地连接——订阅者始终与Broker保持在线状态。因此发布者重连后发送的缓存消息会被Broker直接转发给订阅者,这与clean session特性无关。
原因拆解
- 本地回环不受以太网断开影响:订阅者与Broker的连接基于
127.0.0.1,属于本地通信,断开物理以太网不会中断该连接,Broker始终判定订阅者在线。 - TCP缓存机制:发布者断连时发送的QoS0消息会被操作系统TCP栈缓存,待网络恢复后,TCP会自动将缓存消息发送给Broker。
- clean session的作用边界:clean session仅在订阅者真正断开与Broker的连接且会话超时后生效——Broker会清除该订阅者的会话状态(包括订阅关系),此时收到的消息会被丢弃。但你的测试中订阅者从未断开,clean session未触发作用。
正确测试方法与解决方案
1. 模拟订阅者与Broker的真实断开
要验证clean session的效果,需让订阅者主动断开与Broker的连接,例如:
- 直接停止
mosquitto_sub进程; - 使用工具阻断本地连接,如执行
tcpkill -i lo port 1883(需安装tcpkill); - 临时禁用回环接口(谨慎操作:执行
sudo ifconfig lo down,测试后恢复sudo ifconfig lo up)。
2. 配置短Keepalive加速断开检测
为让Broker快速识别订阅者离线,给订阅者设置短Keepalive时间:
mosquitto_sub -q 0 -t test -k 5
Broker会在1.5倍Keepalive时间(即7.5秒)后判定订阅者离线,清除其会话(因clean session=true)。此时发布者发送的消息会被Broker直接丢弃,订阅者重连后不会收到断开期间的消息。
3. 理解QoS与消息流转逻辑
- QoS0消息是“至多一次”,发布者不等待Broker确认,TCP会负责缓存重传;若需避免断连时的消息缓存,需发布者主动检测网络状态(如通过Keepalive)并停止发送。
- 若使用QoS1/2,Broker会缓存消息直到订阅者上线,但clean session=true时,订阅者断开后Broker会清除会话,缓存的消息也会被丢弃。
原始测试信息
测试步骤
- 收发机器通过以太网连接,模拟断连场景
- 接收端启动Mosquitto:
mosquitto -v -c /etc/mosquitto/mosquitto.conf - 接收端启动mosquitto_sub:
mosquitto_sub -q 0 -t test - 发送端启动终端模式的mosquitto_pub:
mosquitto_pub -q 0 -t test -d -h <ipAddress> -l - 发送3条消息,订阅者正常接收
- 手动断开以太网电缆
- 再发送3条消息,订阅者未接收
- 重新连接电缆,预期订阅者不会收到最后3条消息,但实际仍收到。
补充信息
- 订阅者和发布者均使用QoS 0,尝试强制消息不保留,QoS1/2组合测试结果一致
- 根据Mosquitto文档,broker、发布者、订阅者默认启用clean session,无显式设置选项,仅可通过持久化标志禁用
- 曾尝试为接收端设置短keepalive(1s),但mosquitto_pub的-l和-k参数无法同时使用
日志
mosquitto_pub日志
Client mosq-q9b2Lbd1tARoQKJssX sending CONNECT Client mosq-q9b2Lbd1tARoQKJssX received CONNACK (0) one Client mosq-q9b2Lbd1tARoQKJssX sending PUBLISH (d0, q0, r0, m1, 'test', ... (3 bytes)) two Client mosq-q9b2Lbd1tARoQKJssX sending PUBLISH (d0, q0, r0, m2, 'test', ... (3 bytes)) three Client mosq-q9b2Lbd1tARoQKJssX sending PUBLISH (d0, q0, r0, m3, 'test', ... (5 bytes)) #此处断开电缆并发送最后3条消息 4 Client mosq-q9b2Lbd1tARoQKJssX sending PUBLISH (d0, q0, r0, m4, 'test', ... (1 bytes)) five Client mosq-q9b2Lbd1tARoQKJssX sending PUBLISH (d0, q0, r0, m5, 'test', ... (4 bytes)) six Client mosq-q9b2Lbd1tARoQKJssX sending PUBLISH (d0, q0, r0, m6, 'test', ... (3 bytes))
mosquitto日志
1719010537: mosquitto version 1.4.15 (build date Tue, 18 Jun 2019 11:42:22 -0300) starting 1719010537: Config loaded from /etc/mosquitto/mosquitto.conf. 1719010537: Opening websockets listen socket on port 9001. 1719010537: Opening ipv4 listen socket on port 1883. 1719010537: Opening ipv6 listen socket on port 1883. 1719010537: New connection from <receiver> on port 1883. 1719010537: New client connected from <receiver> as mosq-Wze2t5NWmKTwMdQOzi (c1, k60). 1719010537: Sending CONNACK to mosq-Wze2t5NWmKTwMdQOzi (0, 0) 1719010573: Socket error on client mosq-Wze2t5NWmKTwMdQOzi, disconnecting. 1719010587: New connection from <sender> on port 1883. 1719010587: New client connected from <sender> as mosq-q9b2Lbd1tARoQKJssX (c1, k60). 1719010587: Sending CONNACK to mosq-q9b2Lbd1tARoQKJssX (0, 0) 1719010595: New connection from 127.0.0.1 on port 1883. 1719010595: New client connected from 127.0.0.1 as mosqsub|30731-MichaelJe (c1, k60). 1719010595: Sending CONNACK to mosqsub|30731-MichaelJe (0, 0) 1719010595: Received SUBSCRIBE from mosqsub|30731-MichaelJe 1719010595: test (QoS 0) 1719010595: mosqsub|30731-MichaelJe 0 test 1719010595: Sending SUBACK to mosqsub|30731-MichaelJe #前3条消息: 1719010599: Received PUBLISH from mosq-q9b2Lbd1tARoQKJssX (d0, q0, r0, m0, 'test', ... (3 bytes)) 1719010599: Sending PUBLISH to mosqsub|30731-MichaelJe (d0, q0, r0, m0, 'test', ... (3 bytes)) 1719010601: Received PUBLISH from mosq-q9b2Lbd1tARoQKJssX (d0, q0, r0, m0, 'test', ... (3 bytes)) 1719010601: Sending PUBLISH to mosqsub|30731-MichaelJe (d0, q0, r0, m0, 'test', ... (3 bytes)) 1719010602: Received PUBLISH from mosq-q9b2Lbd1tARoQKJssX (d0, q0, r0, m0, 'test', ... (5 bytes)) 1719010602: Sending PUBLISH to mosqsub|30731-MichaelJe (d0, q0, r0, m0, 'test', ... (5 bytes)) #此处断开电缆 #无操作 #重连后 1719010634: Received PUBLISH from mosq-q9b2Lbd1tARoQKJssX (d0, q0, r0, m0, 'test', ... (1 bytes)) 1719010634: Sending PUBLISH to mosqsub|30731-MichaelJe (d0, q0, r0, m0, 'test', ... (1 bytes)) 1719010634: Received PUBLISH from mosq-q9b2Lbd1tARoQKJssX (d0, q0, r0, m0, 'test', ... (4 bytes)) 1719010634: Sending PUBLISH to mosqsub|30731-MichaelJe (d0, q0, r0, m0, 'test', ... (4 bytes)) 1719010634: Received PUBLISH from mosq-q9b2Lbd1tARoQKJssX (d0, q0, r0, m0, 'test', ... (3 bytes)) 1719010634: Sending PUBLISH to mosqsub|30731-MichaelJe (d0, q0, r0, m0, 'test', ... (3 bytes))
mosquitto_sub日志
one two three #此处断开电缆 #无操作 #重连后 4 five six
内容的提问来源于stack exchange,提问作者Barsaas
相关产品推荐
相关产品推荐

