增强 MQTT 消息拒绝诊断功能

问题:
- TCP_NODELAY 修复了 TCP ACK 延迟,但设备仍然重发
- 需要确定是消息被服务器拒绝,还是设备端 bug

改进内容:
- OnPublish 中添加详细的拒绝日志输出
- 当消息验证失败时,输出 client_id、topic、qos、错误原因
- 当消息被屏蔽时,输出屏蔽类型和原因
- 帮助快速诊断 QoS0 重发的根本原因

新增文档:
- doc/QOS0_RETRANSMIT_ANALYSIS.md - 深度分析重发问题的各种原因
- doc/DIAGNOSTIC_GUIDE.md - 完整的诊断指南和解决方案

使用方法:
  ./meshtastic_mqtt_server --console-log-mqtt=true

观察日志中是否有:
  [mqtt] PUBLISH rejected: ... - 消息被拒绝(服务器问题)
  [mqtt] PUBLISH blocked: ... - 消息被屏蔽(配置问题)

如果没有 rejected/blocked 日志但仍重发,则是设备端 bug。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-06-23 21:42:50 +08:00
co-authored by Claude Fable 5
parent 57cca6bb7a
commit bce6b70e8f
3 changed files with 519 additions and 0 deletions
+12
View File
@@ -203,6 +203,12 @@ func (h *meshtasticFilterHook) OnPublish(cl *mqtt.Client, pk packets.Packet) (pa
PKIKeyResolver: h.pkiResolver,
})
if !valid {
// 记录拒绝原因,帮助诊断 QoS0 重发问题
if h.consoleLog {
info := mqttClientInfoFromClient(cl)
fmt.Fprintf(os.Stderr, "[mqtt] PUBLISH rejected: client_id=%s topic=%s qos=%d payload_len=%d error=%v\n",
info.ClientID, pk.TopicName, pk.FixedHeader.Qos, len(pk.Payload), record["error"])
}
h.rejectPublish(cl, pk, record)
return pk, packets.ErrRejectPacket
}
@@ -210,6 +216,12 @@ func (h *meshtasticFilterHook) OnPublish(cl *mqtt.Client, pk packets.Packet) (pa
for key, value := range violation {
record[key] = value
}
// 记录屏蔽原因
if h.consoleLog {
info := mqttClientInfoFromClient(cl)
fmt.Fprintf(os.Stderr, "[mqtt] PUBLISH blocked: client_id=%s topic=%s type=%v reason=%v\n",
info.ClientID, pk.TopicName, violation["blocking_type"], violation["error"])
}
h.rejectPublish(cl, pk, record)
return pk, packets.ErrRejectPacket
}