MqttNet - MQTT 客户端无法接收 MQTT 服务器发布的所有消息
MqttNet - MQTT Client cannot receive all the messages that were published by an MQTT Server
当客户端订阅主题时,我从 MQTT 服务器发布了 1000 条消息。 MQTT 客户端未收到某些消息。这是一个错误还是我执行的有误?
这里是服务器和客户端配置示例。
服务器配置
using MQTTnet;
using MQTTnet.Server;
using System;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace MqttNetServerExample
{
class Program
{
private static IMqttServer _mqttServer;
static void Main(string[] args)
{
// Configure MQTT server.
var optionsBuilder = new MqttServerOptionsBuilder().WithConnectionBacklog(100)
.WithDefaultEndpointPort(1884);
// Define a mqttServer
_mqttServer = new MqttFactory().CreateMqttServer();
// Message arrived configuration
_mqttServer.UseApplicationMessageReceivedHandler(async e =>
{
if (Encoding.UTF8.GetString(e.ApplicationMessage.Payload)== "Test Message")
{
Console.WriteLine("subscription message received");
Console.WriteLine("Simulating messages...");
await Simulate();
}
});
// When a new client connected
_mqttServer.UseClientConnectedHandler(e =>
{
Console.WriteLine("***** CLIENT CONNECTED : " + e.ClientId + " *******");
});
// Start the mqtt server
_mqttServer.StartAsync(optionsBuilder.Build());
Console.ReadLine();
}
private static async Task PublishMessage(string message)
{
// Create mqttMessage
var mqttMessage = new MqttApplicationMessageBuilder()
.WithTopic("mqttServerTopic")
.WithPayload(message)
.WithAtLeastOnceQoS()
.WithRetainFlag(false)
.WithDupFlag(false)
.Build();
// Publish the message asynchronously
var result = await _mqttServer.PublishAsync(mqttMessage, CancellationToken.None);
if(result.ReasonCode == MQTTnet.Client.Publishing.MqttClientPublishReasonCode.Success)
Console.WriteLine("Message published : " + message);
}
private static async Task Simulate()
{
for (int i = 0; i < 1000; i++)
{
var message = "This is a message from server " + i.ToString();
await PublishMessage(message);
}
}
}
}
客户端配置
using MQTTnet;
using MQTTnet.Client;
using MQTTnet.Client.Options;
using MQTTnet.Client.Subscribing;
using System;
using System.Text;
using System.Threading;
namespace MqttNetClientExample
{
class Program
{
private static IMqttClient _mqttClient;
static void Main(string[] args)
{
// Create client
_mqttClient = new MqttFactory().CreateMqttClient();
var options = new MqttClientOptionsBuilder().WithClientId("MqttClient")
.WithTcpServer("localhost", 1884)
.Build();
// When client connected to the server
_mqttClient.UseConnectedHandler(async e =>
{
// Subscribe to a topic
MqttClientSubscribeResult subResult = await _mqttClient.SubscribeAsync(new MqttClientSubscribeOptionsBuilder()
.WithTopicFilter("mqttServerTopic")
.Build());
// Sen a test message to the server
PublishMessage("Test Message");
});
// When client received a message from server
_mqttClient.UseApplicationMessageReceivedHandler(e =>
{
Console.WriteLine($"+ Payload = {Encoding.UTF8.GetString(e.ApplicationMessage.Payload)}");
});
// Connect ot server
_mqttClient.ConnectAsync(options, CancellationToken.None);
Console.Read();
}
private static async void PublishMessage(string message)
{
// Create mqttMessage
var mqttMessage = new MqttApplicationMessageBuilder()
.WithTopic("mqttServerTopic")
.WithPayload(message)
.WithExactlyOnceQoS()
.Build();
// Publish the message asynchronously
await _mqttClient.PublishAsync(mqttMessage, CancellationToken.None);
}
}
}
结果输出样本
这是客户端应用程序的示例输出:
+ Payload = Test Message
+ Payload = This is a message from server 0
+ Payload = This is a message from server 1
+ Payload = This is a message from server 2
+ Payload = This is a message from server 3
+ Payload = This is a message from server 4
+ Payload = This is a message from server 5
+ Payload = This is a message from server 6
+ Payload = This is a message from server 7
+ Payload = This is a message from server 8
+ Payload = This is a message from server 9
+ Payload = This is a message from server 10
+ Payload = This is a message from server 11
+ Payload = This is a message from server 13
+ Payload = This is a message from server 14
+ Payload = This is a message from server 23
+ Payload = This is a message from server 53
+ Payload = This is a message from server 54
+ Payload = This is a message from server 55
+ Payload = This is a message from server 56
+ Payload = This is a message from server 57
+ Payload = This is a message from server 83
+ Payload = This is a message from server 105
+ Payload = This is a message from server 120
+ Payload = This is a message from server 138
+ Payload = This is a message from server 139
+ Payload = This is a message from server 140
+ Payload = This is a message from server 141
+ Payload = This is a message from server 172
+ Payload = This is a message from server 192
+ Payload = This is a message from server 207
+ Payload = This is a message from server 218
+ Payload = This is a message from server 236
+ Payload = This is a message from server 258
+ Payload = This is a message from server 278
+ Payload = This is a message from server 302
.
.
.
.
+ Payload = This is a message from server 999
如您所见,一些消息丢失了。我怎样才能毫无损失地获取所有消息?谢谢
根据评论,问题出在 MqttNet Broker 的配置上。
设置MaxPendingMessagesPerClient
默认为250
,这意味着当特定客户端有250条消息等待传递时,当另一条消息到达时,队列中的第一条消息将被丢弃。
您的应用程序发送消息的速度超过了接收方处理消息的速度,因此队列建立得很快并且消息丢失了。最后 250 条消息毫无问题地到达,因为没有发送任何新消息(因此代理不需要丢弃更多消息)。
要解决此问题,您可以使用 WithMaxPendingMessagesPerClient
例如
var optionsBuilder = new MqttServerOptionsBuilder()
.WithMaxPendingMessagesPerClient(1000);
注意:在生产中用于此设置的值将取决于您的具体要求。您需要确保订阅者能够以消息产生的速度消费消息(否则代理队列将不断增长)。
当客户端订阅主题时,我从 MQTT 服务器发布了 1000 条消息。 MQTT 客户端未收到某些消息。这是一个错误还是我执行的有误?
这里是服务器和客户端配置示例。
服务器配置
using MQTTnet;
using MQTTnet.Server;
using System;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace MqttNetServerExample
{
class Program
{
private static IMqttServer _mqttServer;
static void Main(string[] args)
{
// Configure MQTT server.
var optionsBuilder = new MqttServerOptionsBuilder().WithConnectionBacklog(100)
.WithDefaultEndpointPort(1884);
// Define a mqttServer
_mqttServer = new MqttFactory().CreateMqttServer();
// Message arrived configuration
_mqttServer.UseApplicationMessageReceivedHandler(async e =>
{
if (Encoding.UTF8.GetString(e.ApplicationMessage.Payload)== "Test Message")
{
Console.WriteLine("subscription message received");
Console.WriteLine("Simulating messages...");
await Simulate();
}
});
// When a new client connected
_mqttServer.UseClientConnectedHandler(e =>
{
Console.WriteLine("***** CLIENT CONNECTED : " + e.ClientId + " *******");
});
// Start the mqtt server
_mqttServer.StartAsync(optionsBuilder.Build());
Console.ReadLine();
}
private static async Task PublishMessage(string message)
{
// Create mqttMessage
var mqttMessage = new MqttApplicationMessageBuilder()
.WithTopic("mqttServerTopic")
.WithPayload(message)
.WithAtLeastOnceQoS()
.WithRetainFlag(false)
.WithDupFlag(false)
.Build();
// Publish the message asynchronously
var result = await _mqttServer.PublishAsync(mqttMessage, CancellationToken.None);
if(result.ReasonCode == MQTTnet.Client.Publishing.MqttClientPublishReasonCode.Success)
Console.WriteLine("Message published : " + message);
}
private static async Task Simulate()
{
for (int i = 0; i < 1000; i++)
{
var message = "This is a message from server " + i.ToString();
await PublishMessage(message);
}
}
}
}
客户端配置
using MQTTnet;
using MQTTnet.Client;
using MQTTnet.Client.Options;
using MQTTnet.Client.Subscribing;
using System;
using System.Text;
using System.Threading;
namespace MqttNetClientExample
{
class Program
{
private static IMqttClient _mqttClient;
static void Main(string[] args)
{
// Create client
_mqttClient = new MqttFactory().CreateMqttClient();
var options = new MqttClientOptionsBuilder().WithClientId("MqttClient")
.WithTcpServer("localhost", 1884)
.Build();
// When client connected to the server
_mqttClient.UseConnectedHandler(async e =>
{
// Subscribe to a topic
MqttClientSubscribeResult subResult = await _mqttClient.SubscribeAsync(new MqttClientSubscribeOptionsBuilder()
.WithTopicFilter("mqttServerTopic")
.Build());
// Sen a test message to the server
PublishMessage("Test Message");
});
// When client received a message from server
_mqttClient.UseApplicationMessageReceivedHandler(e =>
{
Console.WriteLine($"+ Payload = {Encoding.UTF8.GetString(e.ApplicationMessage.Payload)}");
});
// Connect ot server
_mqttClient.ConnectAsync(options, CancellationToken.None);
Console.Read();
}
private static async void PublishMessage(string message)
{
// Create mqttMessage
var mqttMessage = new MqttApplicationMessageBuilder()
.WithTopic("mqttServerTopic")
.WithPayload(message)
.WithExactlyOnceQoS()
.Build();
// Publish the message asynchronously
await _mqttClient.PublishAsync(mqttMessage, CancellationToken.None);
}
}
}
结果输出样本
这是客户端应用程序的示例输出:
+ Payload = Test Message
+ Payload = This is a message from server 0
+ Payload = This is a message from server 1
+ Payload = This is a message from server 2
+ Payload = This is a message from server 3
+ Payload = This is a message from server 4
+ Payload = This is a message from server 5
+ Payload = This is a message from server 6
+ Payload = This is a message from server 7
+ Payload = This is a message from server 8
+ Payload = This is a message from server 9
+ Payload = This is a message from server 10
+ Payload = This is a message from server 11
+ Payload = This is a message from server 13
+ Payload = This is a message from server 14
+ Payload = This is a message from server 23
+ Payload = This is a message from server 53
+ Payload = This is a message from server 54
+ Payload = This is a message from server 55
+ Payload = This is a message from server 56
+ Payload = This is a message from server 57
+ Payload = This is a message from server 83
+ Payload = This is a message from server 105
+ Payload = This is a message from server 120
+ Payload = This is a message from server 138
+ Payload = This is a message from server 139
+ Payload = This is a message from server 140
+ Payload = This is a message from server 141
+ Payload = This is a message from server 172
+ Payload = This is a message from server 192
+ Payload = This is a message from server 207
+ Payload = This is a message from server 218
+ Payload = This is a message from server 236
+ Payload = This is a message from server 258
+ Payload = This is a message from server 278
+ Payload = This is a message from server 302
.
.
.
.
+ Payload = This is a message from server 999
如您所见,一些消息丢失了。我怎样才能毫无损失地获取所有消息?谢谢
根据评论,问题出在 MqttNet Broker 的配置上。
设置MaxPendingMessagesPerClient
默认为250
,这意味着当特定客户端有250条消息等待传递时,当另一条消息到达时,队列中的第一条消息将被丢弃。
您的应用程序发送消息的速度超过了接收方处理消息的速度,因此队列建立得很快并且消息丢失了。最后 250 条消息毫无问题地到达,因为没有发送任何新消息(因此代理不需要丢弃更多消息)。
要解决此问题,您可以使用 WithMaxPendingMessagesPerClient
例如
var optionsBuilder = new MqttServerOptionsBuilder()
.WithMaxPendingMessagesPerClient(1000);
注意:在生产中用于此设置的值将取决于您的具体要求。您需要确保订阅者能够以消息产生的速度消费消息(否则代理队列将不断增长)。