You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

MQTTNet获取3D打印机状态重复打印问题求助

问题原因

你代码里的核心问题是在while循环内部重复订阅ApplicationMessageReceivedAsync事件。每次执行mqttClient.ApplicationMessageReceivedAsync += ...时,都会给这个事件追加一个新的处理委托,而非替换已有的。当MQTT客户端收到消息时,所有已添加的委托都会被依次执行,所以第一次循环加1个委托,第二次加第2个,最终导致消息打印次数逐次递增。

解决方法

把事件订阅代码移到while循环外面,只执行一次即可。如果需要在取消监听时移除事件处理,可在取消逻辑中完成:

static async Task ObserverAsync(IMqttClient mqttClient, CancellationToken cancellationToken)
{
    // 提前定义事件处理委托,方便后续移除操作
    Func<MqttApplicationMessageReceivedEventArgs, Task> messageHandler = e =>
    {
        var msg = Encoding.UTF8.GetString(e.ApplicationMessage.PayloadSegment);
        if (/*significant condition*/)
        {
            Console.WriteLine($"Received message: {msg}");
        }
        return Task.CompletedTask;
    };

    try
    {
        // 仅订阅一次事件,放在循环外部
        mqttClient.ApplicationMessageReceivedAsync += messageHandler;

        while (!cancellationToken.IsCancellationRequested)
        {
            await Task.Delay(TimeSpan.FromSeconds(2), cancellationToken);
            
            // 如果是主动向打印机请求状态,可在此添加发送MQTT消息的代码,示例:
            // var requestMsg = new MqttApplicationMessageBuilder()
            //     .WithTopic("printer/query/status")
            //     .WithPayload("get-status")
            //     .Build();
            // await mqttClient.PublishAsync(requestMsg, cancellationToken);
        }
    }
    catch(TaskCanceledException)
    {
        Console.WriteLine("Observer Disabled");
    }
    finally
    {
        // 取消监听时移除事件处理,避免内存泄漏
        mqttClient.ApplicationMessageReceivedAsync -= messageHandler;
    }
}
额外说明
  • MQTT事件订阅是持久化的,一旦完成订阅,只要客户端保持连接,后续收到对应主题的消息都会触发处理委托,无需重复订阅。
  • 如果你的逻辑是每2秒主动向打印机请求状态,循环内应该执行发送请求消息的操作,事件订阅只需要一次,用来接收打印机返回的状态响应。
  • 事件的+=是追加委托,-=是移除指定委托,提前保存委托引用,能在finally块中准确移除,避免内存泄漏。

内容的提问来源于stack exchange,提问作者Cybeast Gregar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 03:52:41