简体   繁体   English

遗漏保留的 MQTT 消息

[英]Retained MQTT messages being missed

I am trying to create a simple application that will publish some messages to a topic with MQTT (library I am using is M2Mqtt.net) and then I want to subscribe to the topic once the messages have already been sent and then have them all be received and then discarded, because they have been received.我正在尝试创建一个简单的应用程序,它将使用 MQTT(我正在使用的库是 M2Mqtt.net)将一些消息发布到主题,然后我想在消息已经发送后订阅该主题,然后将它们全部发送收到然后丢弃,因为它们已经收到。

I am using mosquitto 2.0.12 as the broker我使用 mosquitto 2.0.12作为代理

This is the publisher:这是发布者:

public class MessagePublisher : IMessagePublisher
{
    private readonly MqttClient _client;

    public MessagePublisher()
    {
        _client = new MqttClient("localhost");

        // clean session needs to be set to false so that it retains all the missed messages, not just the last one
        _client.Connect(Guid.NewGuid().ToString(), "username", "password", false, byte.MaxValue);
    }

    public void Publish(string topic, string message, bool retain = false)
    {
        Console.Write($"Sent: {topic}, {message}");

        _client.Publish(topic, Encoding.UTF8.GetBytes(message), MqttMsgBase.QOS_LEVEL_EXACTLY_ONCE, retain);

        Total.SentAndReceived.Add(message, null);
    }
}

This is the listener:这是听众:

public class MessageReceiver : IMessageReceiver
{
    private readonly MqttClient _client;

    public MessageReceiver()
    {
        _client = new MqttClient("localhost");
    }

    public void Subscribe(params string[] topics)
    {
        _client.Subscribe(topics, new[] { MqttMsgBase.QOS_LEVEL_EXACTLY_ONCE });

        _client.MqttMsgPublishReceived += client_receivedMessage;
    }


    public void Connect()
    {
        // clean session needs to be set to false so that it retains all the missed messages, not just the last one
        _client.Connect(Guid.NewGuid().ToString(), "username", "password", false, byte.MaxValue);
    }

    public void Disconnect()
    {
        _client.Disconnect();
    }

    static void client_receivedMessage(object sender, MqttMsgPublishEventArgs e)
    {
        var message = Encoding.Default.GetString(e.Message);

        Console.WriteLine($"Message Received: {message}");

        if (Total.SentAndReceived.ContainsKey(message))
            Total.SentAndReceived[message] = message;
    }
}

And this is the main application:这是主要的应用程序:

public static class Program
{
    public static void Main(string[] args)
    {
        var messageReceiver = new MessageReceiver();

        var publisher = new MessagePublisher();

        for (var i = 1; i <= 10000; i++)
        {
            publisher.Publish("Devices/", i.ToString(), true);
        }

        messageReceiver.Subscribe("Devices/");

        messageReceiver.Connect();

        Thread.Sleep(5000);

        var b = Total.SentAndReceived.Where(x => x.Value == null);

        Console.WriteLine($"{b.Count()} Missed Messages");
    }
}

The problem I am having is that there are missed messages.我遇到的问题是有遗漏的消息。 And the number of missed messages always changes when I run the application.当我运行应用程序时,错过消息的数量总是会发生变化。 And it's not that last n messages being missed it's the first n messages.并不是错过了最后 n 条消息,而是错过了前 n 条消息。

I hope that if I was to build a service that would listen to the published messages.我希望如果我要构建一个可以收听已发布消息的服务。 If the services stops for any reason.如果服务因任何原因停止。 Once the service comes back online, the messages sent in that downtime would be received.一旦服务重新上线,就会收到在该停机时间内发送的消息。

I think you have a misunderstanding around some terms here.我认为你对这里的一些术语有误解。

First, MQTT does not generally queue messages.首先,MQTT 一般不会对消息进行排队。 The only time the broker will queue messages is if the receiving client has already already been connected and subscribed to the topic at QOS > 0. If that client then disconnects before the publisher sends the messages the broker will queue the messages.代理将消息排队的唯一时间是如果接收客户端已经连接并订阅了 QOS > 0 的主题。如果该客户端在发布者发送消息之前断开连接,代理将消息排队。 They will then only be sent to the receiving client if they then reconnect with the same client id and have the clean session flag set to false.如果他们随后使用相同的客户端 ID 重新连接并将干净的 session 标志设置为 false,则它们只会被发送到接收客户端。 This is the only way that messages will be queued up.这是消息排队的唯一方式。

Since you appear to be using randomly generated client ids ( Guid.NewGuid().ToString() ) this will not work.由于您似乎正在使用随机生成的客户端 ID( Guid.NewGuid().ToString() ),这将不起作用。 You also appear to be trying to subscribe before you connect, again that won't work.您似乎还在尝试在连接之前进行订阅,但同样行不通。

Secondly, retained messages have nothing to do with message queuing as described above.其次,保留消息与上面描述的消息队列无关。 A message is retained if the retained flag is set at the point of publishing.如果在发布时设置了保留标志,则会保留一条消息。 The broker will then store that specific message and deliver it ever time a client subscribes to the matching topic.然后代理将存储该特定消息并在客户端订阅匹配主题时传递它。 This message will be sent before any other messages on the topic.此消息将在有关该主题的任何其他消息之前发送。 If another message with the retained flag is published it will replace the previous message, there can only be 1 retained message per topic.如果发布了另一条带有保留标志的消息,它将替换之前的消息,每个主题只能有 1 条保留消息。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM