mirror of
https://github.com/dotnet/MQTTnet.git
synced 2026-10-30 02:38:53 +08:00
Refactor keep alive monitoring and add unit tests.
This commit is contained in:
@@ -14,6 +14,7 @@
|
|||||||
* [Client] The _ManagedClient_ now supports unsubscribing (thanks to @lerppana)
|
* [Client] The _ManagedClient_ now supports unsubscribing (thanks to @lerppana)
|
||||||
* [Server] Fixed some minor async issues.
|
* [Server] Fixed some minor async issues.
|
||||||
* [Server] Fixed wrong comparison of the topic and QoS for retained messages.
|
* [Server] Fixed wrong comparison of the topic and QoS for retained messages.
|
||||||
|
* [Server] Added a property which provides access to the used options (read only).
|
||||||
</releaseNotes>
|
</releaseNotes>
|
||||||
<copyright>Copyright Christian Kratky 2016-2018</copyright>
|
<copyright>Copyright Christian Kratky 2016-2018</copyright>
|
||||||
<tags>MQTT Message Queue Telemetry Transport MQTTClient MQTTServer Server MQTTBroker Broker NETStandard IoT InternetOfThings Messaging Hardware Arduino Sensor Actuator M2M ESP Smart Home Cities Automation Xamarin</tags>
|
<tags>MQTT Message Queue Telemetry Transport MQTTClient MQTTServer Server MQTTBroker Broker NETStandard IoT InternetOfThings Messaging Hardware Arduino Sensor Actuator M2M ESP Smart Home Cities Automation Xamarin</tags>
|
||||||
|
|||||||
@@ -13,6 +13,8 @@ namespace MQTTnet.Server
|
|||||||
event EventHandler<MqttClientSubscribedTopicEventArgs> ClientSubscribedTopic;
|
event EventHandler<MqttClientSubscribedTopicEventArgs> ClientSubscribedTopic;
|
||||||
event EventHandler<MqttClientUnsubscribedTopicEventArgs> ClientUnsubscribedTopic;
|
event EventHandler<MqttClientUnsubscribedTopicEventArgs> ClientUnsubscribedTopic;
|
||||||
|
|
||||||
|
IMqttServerOptions Options { get; }
|
||||||
|
|
||||||
Task<IList<ConnectedMqttClient>> GetConnectedClientsAsync();
|
Task<IList<ConnectedMqttClient>> GetConnectedClientsAsync();
|
||||||
|
|
||||||
Task SubscribeAsync(string clientId, IList<TopicFilter> topicFilters);
|
Task SubscribeAsync(string clientId, IList<TopicFilter> topicFilters);
|
||||||
|
|||||||
@@ -0,0 +1,88 @@
|
|||||||
|
using System;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using MQTTnet.Diagnostics;
|
||||||
|
using MQTTnet.Packets;
|
||||||
|
|
||||||
|
namespace MQTTnet.Server
|
||||||
|
{
|
||||||
|
public sealed class MqttClientKeepAliveMonitor
|
||||||
|
{
|
||||||
|
private readonly Stopwatch _lastPacketReceivedTracker = new Stopwatch();
|
||||||
|
private readonly Stopwatch _lastNonKeepAlivePacketReceivedTracker = new Stopwatch();
|
||||||
|
|
||||||
|
private readonly string _clientId;
|
||||||
|
private readonly Func<Task> _timeoutCallback;
|
||||||
|
private readonly IMqttNetLogger _logger;
|
||||||
|
|
||||||
|
public MqttClientKeepAliveMonitor(string clientId, Func<Task> timeoutCallback, IMqttNetLogger logger)
|
||||||
|
{
|
||||||
|
_clientId = clientId;
|
||||||
|
_timeoutCallback = timeoutCallback;
|
||||||
|
_logger = logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TimeSpan LastPacketReceived => _lastPacketReceivedTracker.Elapsed;
|
||||||
|
|
||||||
|
public TimeSpan LastNonKeepAlivePacketReceived => _lastNonKeepAlivePacketReceivedTracker.Elapsed;
|
||||||
|
|
||||||
|
public void Start(int keepAlivePeriod, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
if (keepAlivePeriod == 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Task.Run(async () => await RunAsync(keepAlivePeriod, cancellationToken).ConfigureAwait(false), cancellationToken).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task RunAsync(int keepAlivePeriod, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_lastPacketReceivedTracker.Restart();
|
||||||
|
_lastNonKeepAlivePacketReceivedTracker.Restart();
|
||||||
|
|
||||||
|
while (!cancellationToken.IsCancellationRequested)
|
||||||
|
{
|
||||||
|
// Values described here: [MQTT-3.1.2-24].
|
||||||
|
if (_lastPacketReceivedTracker.Elapsed.TotalSeconds > keepAlivePeriod * 1.5D)
|
||||||
|
{
|
||||||
|
_logger.Warning<MqttClientSession>("Client '{0}': Did not receive any packet or keep alive signal.", _clientId);
|
||||||
|
|
||||||
|
if (_timeoutCallback != null)
|
||||||
|
{
|
||||||
|
await _timeoutCallback().ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await Task.Delay(keepAlivePeriod, cancellationToken).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (OperationCanceledException)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
catch (Exception exception)
|
||||||
|
{
|
||||||
|
_logger.Error<MqttClientSession>(exception, "Client '{0}': Unhandled exception while checking keep alive timeouts.", _clientId);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
_logger.Trace<MqttClientSession>("Client {0}: Stopped checking keep alive timeout.", _clientId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void PacketReceived(MqttBasePacket packet)
|
||||||
|
{
|
||||||
|
_lastPacketReceivedTracker.Restart();
|
||||||
|
|
||||||
|
if (!(packet is MqttPingReqPacket))
|
||||||
|
{
|
||||||
|
_lastNonKeepAlivePacketReceivedTracker.Restart();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using MQTTnet.Adapter;
|
using MQTTnet.Adapter;
|
||||||
@@ -15,12 +14,8 @@ namespace MQTTnet.Server
|
|||||||
{
|
{
|
||||||
public sealed class MqttClientSession : IDisposable
|
public sealed class MqttClientSession : IDisposable
|
||||||
{
|
{
|
||||||
private readonly Stopwatch _lastPacketReceivedTracker = Stopwatch.StartNew();
|
|
||||||
private readonly Stopwatch _lastNonKeepAlivePacketReceivedTracker = Stopwatch.StartNew();
|
|
||||||
|
|
||||||
private readonly IMqttServerOptions _options;
|
private readonly IMqttServerOptions _options;
|
||||||
private readonly IMqttNetLogger _logger;
|
private readonly IMqttNetLogger _logger;
|
||||||
|
|
||||||
private readonly MqttRetainedMessagesManager _retainedMessagesManager;
|
private readonly MqttRetainedMessagesManager _retainedMessagesManager;
|
||||||
|
|
||||||
private IMqttChannelAdapter _adapter;
|
private IMqttChannelAdapter _adapter;
|
||||||
@@ -38,7 +33,8 @@ namespace MQTTnet.Server
|
|||||||
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
||||||
|
|
||||||
ClientId = clientId;
|
ClientId = clientId;
|
||||||
|
|
||||||
|
KeepAliveMonitor = new MqttClientKeepAliveMonitor(clientId, StopDueToKeepAliveTimeoutAsync, _logger);
|
||||||
SubscriptionsManager = new MqttClientSubscriptionsManager(_options, clientId);
|
SubscriptionsManager = new MqttClientSubscriptionsManager(_options, clientId);
|
||||||
PendingMessagesQueue = new MqttClientPendingMessagesQueue(_options, this, _logger);
|
PendingMessagesQueue = new MqttClientPendingMessagesQueue(_options, this, _logger);
|
||||||
}
|
}
|
||||||
@@ -49,14 +45,12 @@ namespace MQTTnet.Server
|
|||||||
|
|
||||||
public MqttClientPendingMessagesQueue PendingMessagesQueue { get; }
|
public MqttClientPendingMessagesQueue PendingMessagesQueue { get; }
|
||||||
|
|
||||||
|
public MqttClientKeepAliveMonitor KeepAliveMonitor { get; }
|
||||||
|
|
||||||
public string ClientId { get; }
|
public string ClientId { get; }
|
||||||
|
|
||||||
public MqttProtocolVersion? ProtocolVersion => _adapter?.PacketSerializer.ProtocolVersion;
|
public MqttProtocolVersion? ProtocolVersion => _adapter?.PacketSerializer.ProtocolVersion;
|
||||||
|
|
||||||
public TimeSpan LastPacketReceived => _lastPacketReceivedTracker.Elapsed;
|
|
||||||
|
|
||||||
public TimeSpan LastNonKeepAlivePacketReceived => _lastNonKeepAlivePacketReceivedTracker.Elapsed;
|
|
||||||
|
|
||||||
public bool IsConnected => _adapter != null;
|
public bool IsConnected => _adapter != null;
|
||||||
|
|
||||||
public async Task RunAsync(MqttConnectPacket connectPacket, IMqttChannelAdapter adapter)
|
public async Task RunAsync(MqttConnectPacket connectPacket, IMqttChannelAdapter adapter)
|
||||||
@@ -73,14 +67,7 @@ namespace MQTTnet.Server
|
|||||||
_cancellationTokenSource = cancellationTokenSource;
|
_cancellationTokenSource = cancellationTokenSource;
|
||||||
|
|
||||||
PendingMessagesQueue.Start(adapter, cancellationTokenSource.Token);
|
PendingMessagesQueue.Start(adapter, cancellationTokenSource.Token);
|
||||||
|
KeepAliveMonitor.Start(connectPacket.KeepAlivePeriod, cancellationTokenSource.Token);
|
||||||
_lastPacketReceivedTracker.Restart();
|
|
||||||
_lastNonKeepAlivePacketReceivedTracker.Restart();
|
|
||||||
|
|
||||||
if (connectPacket.KeepAlivePeriod > 0)
|
|
||||||
{
|
|
||||||
StartCheckingKeepAliveTimeout(TimeSpan.FromSeconds(connectPacket.KeepAlivePeriod), cancellationTokenSource.Token);
|
|
||||||
}
|
|
||||||
|
|
||||||
await ReceivePacketsAsync(adapter, cancellationTokenSource.Token).ConfigureAwait(false);
|
await ReceivePacketsAsync(adapter, cancellationTokenSource.Token).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
@@ -123,7 +110,7 @@ namespace MQTTnet.Server
|
|||||||
var willMessage = _willMessage;
|
var willMessage = _willMessage;
|
||||||
if (willMessage != null)
|
if (willMessage != null)
|
||||||
{
|
{
|
||||||
_willMessage = null; //clear willmessage so it is send just once
|
_willMessage = null; // clear willmessage so it is send just once
|
||||||
await ApplicationMessageReceivedCallback(this, willMessage).ConfigureAwait(false);
|
await ApplicationMessageReceivedCallback(this, willMessage).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -161,12 +148,10 @@ namespace MQTTnet.Server
|
|||||||
{
|
{
|
||||||
if (topicFilters == null) throw new ArgumentNullException(nameof(topicFilters));
|
if (topicFilters == null) throw new ArgumentNullException(nameof(topicFilters));
|
||||||
|
|
||||||
var response = SubscriptionsManager.UnsubscribeAsync(new MqttUnsubscribePacket
|
return SubscriptionsManager.UnsubscribeAsync(new MqttUnsubscribePacket
|
||||||
{
|
{
|
||||||
TopicFilters = topicFilters
|
TopicFilters = topicFilters
|
||||||
});
|
});
|
||||||
|
|
||||||
return response;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
@@ -179,6 +164,12 @@ namespace MQTTnet.Server
|
|||||||
_cancellationTokenSource?.Dispose();
|
_cancellationTokenSource?.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Task StopDueToKeepAliveTimeoutAsync()
|
||||||
|
{
|
||||||
|
_logger.Info<MqttClientSession>("Client '{0}': Timeout while waiting for KeepAlive packet.", ClientId);
|
||||||
|
return StopAsync();
|
||||||
|
}
|
||||||
|
|
||||||
private async Task ReceivePacketsAsync(IMqttChannelAdapter adapter, CancellationToken cancellationToken)
|
private async Task ReceivePacketsAsync(IMqttChannelAdapter adapter, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@@ -186,14 +177,7 @@ namespace MQTTnet.Server
|
|||||||
while (!cancellationToken.IsCancellationRequested)
|
while (!cancellationToken.IsCancellationRequested)
|
||||||
{
|
{
|
||||||
var packet = await adapter.ReceivePacketAsync(TimeSpan.Zero, cancellationToken).ConfigureAwait(false);
|
var packet = await adapter.ReceivePacketAsync(TimeSpan.Zero, cancellationToken).ConfigureAwait(false);
|
||||||
|
KeepAliveMonitor.PacketReceived(packet);
|
||||||
_lastPacketReceivedTracker.Restart();
|
|
||||||
|
|
||||||
if (!(packet is MqttPingReqPacket))
|
|
||||||
{
|
|
||||||
_lastNonKeepAlivePacketReceivedTracker.Restart();
|
|
||||||
}
|
|
||||||
|
|
||||||
await ProcessReceivedPacketAsync(adapter, packet, cancellationToken).ConfigureAwait(false);
|
await ProcessReceivedPacketAsync(adapter, packet, cancellationToken).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -335,42 +319,5 @@ namespace MQTTnet.Server
|
|||||||
var response = new MqttPubCompPacket { PacketIdentifier = pubRelPacket.PacketIdentifier };
|
var response = new MqttPubCompPacket { PacketIdentifier = pubRelPacket.PacketIdentifier };
|
||||||
return adapter.SendPacketsAsync(_options.DefaultCommunicationTimeout, cancellationToken, response);
|
return adapter.SendPacketsAsync(_options.DefaultCommunicationTimeout, cancellationToken, response);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void StartCheckingKeepAliveTimeout(TimeSpan keepAlivePeriod, CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
Task.Run(
|
|
||||||
async () => await CheckKeepAliveTimeoutAsync(keepAlivePeriod, cancellationToken).ConfigureAwait(false)
|
|
||||||
, cancellationToken);
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task CheckKeepAliveTimeoutAsync(TimeSpan keepAlivePeriod, CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
while (!cancellationToken.IsCancellationRequested)
|
|
||||||
{
|
|
||||||
// Values described here: [MQTT-3.1.2-24].
|
|
||||||
if (_lastPacketReceivedTracker.Elapsed.TotalSeconds > keepAlivePeriod.TotalSeconds * 1.5D)
|
|
||||||
{
|
|
||||||
_logger.Warning<MqttClientSession>("Client '{0}': Did not receive any packet or keep alive signal.", ClientId);
|
|
||||||
await StopAsync();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
await Task.Delay(keepAlivePeriod, cancellationToken);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (OperationCanceledException)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
catch (Exception exception)
|
|
||||||
{
|
|
||||||
_logger.Error<MqttClientSession>(exception, "Client '{0}': Unhandled exception while checking keep alive timeouts.", ClientId);
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
_logger.Trace<MqttClientSession>("Client {0}: Stopped checking keep alive timeout.", ClientId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -129,8 +129,8 @@ namespace MQTTnet.Server
|
|||||||
{
|
{
|
||||||
ClientId = s.Value.ClientId,
|
ClientId = s.Value.ClientId,
|
||||||
ProtocolVersion = s.Value.ProtocolVersion ?? MqttProtocolVersion.V311,
|
ProtocolVersion = s.Value.ProtocolVersion ?? MqttProtocolVersion.V311,
|
||||||
LastPacketReceived = s.Value.LastPacketReceived,
|
LastPacketReceived = s.Value.KeepAliveMonitor.LastPacketReceived,
|
||||||
LastNonKeepAlivePacketReceived = s.Value.LastNonKeepAlivePacketReceived,
|
LastNonKeepAlivePacketReceived = s.Value.KeepAliveMonitor.LastNonKeepAlivePacketReceived,
|
||||||
PendingApplicationMessages = s.Value.PendingMessagesQueue.Count
|
PendingApplicationMessages = s.Value.PendingMessagesQueue.Count
|
||||||
}).ToList();
|
}).ToList();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ namespace MQTTnet.Server
|
|||||||
private MqttClientSessionsManager _clientSessionsManager;
|
private MqttClientSessionsManager _clientSessionsManager;
|
||||||
private MqttRetainedMessagesManager _retainedMessagesManager;
|
private MqttRetainedMessagesManager _retainedMessagesManager;
|
||||||
private CancellationTokenSource _cancellationTokenSource;
|
private CancellationTokenSource _cancellationTokenSource;
|
||||||
private IMqttServerOptions _options;
|
|
||||||
|
|
||||||
public MqttServer(IEnumerable<IMqttServerAdapter> adapters, IMqttNetLogger logger)
|
public MqttServer(IEnumerable<IMqttServerAdapter> adapters, IMqttNetLogger logger)
|
||||||
{
|
{
|
||||||
@@ -35,6 +34,8 @@ namespace MQTTnet.Server
|
|||||||
|
|
||||||
public event EventHandler<MqttApplicationMessageReceivedEventArgs> ApplicationMessageReceived;
|
public event EventHandler<MqttApplicationMessageReceivedEventArgs> ApplicationMessageReceived;
|
||||||
|
|
||||||
|
public IMqttServerOptions Options { get; private set; }
|
||||||
|
|
||||||
public Task<IList<ConnectedMqttClient>> GetConnectedClientsAsync()
|
public Task<IList<ConnectedMqttClient>> GetConnectedClientsAsync()
|
||||||
{
|
{
|
||||||
return _clientSessionsManager.GetConnectedClientsAsync();
|
return _clientSessionsManager.GetConnectedClientsAsync();
|
||||||
@@ -70,16 +71,16 @@ namespace MQTTnet.Server
|
|||||||
|
|
||||||
public async Task StartAsync(IMqttServerOptions options)
|
public async Task StartAsync(IMqttServerOptions options)
|
||||||
{
|
{
|
||||||
_options = options ?? throw new ArgumentNullException(nameof(options));
|
Options = options ?? throw new ArgumentNullException(nameof(options));
|
||||||
|
|
||||||
if (_cancellationTokenSource != null) throw new InvalidOperationException("The server is already started.");
|
if (_cancellationTokenSource != null) throw new InvalidOperationException("The server is already started.");
|
||||||
|
|
||||||
_cancellationTokenSource = new CancellationTokenSource();
|
_cancellationTokenSource = new CancellationTokenSource();
|
||||||
|
|
||||||
_retainedMessagesManager = new MqttRetainedMessagesManager(_options, _logger);
|
_retainedMessagesManager = new MqttRetainedMessagesManager(Options, _logger);
|
||||||
await _retainedMessagesManager.LoadMessagesAsync();
|
await _retainedMessagesManager.LoadMessagesAsync();
|
||||||
|
|
||||||
_clientSessionsManager = new MqttClientSessionsManager(_options, _retainedMessagesManager, _logger)
|
_clientSessionsManager = new MqttClientSessionsManager(Options, _retainedMessagesManager, _logger)
|
||||||
{
|
{
|
||||||
ClientConnectedCallback = OnClientConnected,
|
ClientConnectedCallback = OnClientConnected,
|
||||||
ClientDisconnectedCallback = OnClientDisconnected,
|
ClientDisconnectedCallback = OnClientDisconnected,
|
||||||
@@ -91,7 +92,7 @@ namespace MQTTnet.Server
|
|||||||
foreach (var adapter in _adapters)
|
foreach (var adapter in _adapters)
|
||||||
{
|
{
|
||||||
adapter.ClientAccepted += OnClientAccepted;
|
adapter.ClientAccepted += OnClientAccepted;
|
||||||
await adapter.StartAsync(_options);
|
await adapter.StartAsync(Options);
|
||||||
}
|
}
|
||||||
|
|
||||||
_logger.Info<MqttServer>("Started.");
|
_logger.Info<MqttServer>("Started.");
|
||||||
@@ -142,7 +143,7 @@ namespace MQTTnet.Server
|
|||||||
_logger.Info<MqttServer>("Client '{0}': Disconnected.", client.ClientId);
|
_logger.Info<MqttServer>("Client '{0}': Disconnected.", client.ClientId);
|
||||||
ClientDisconnected?.Invoke(this, new MqttClientDisconnectedEventArgs(client));
|
ClientDisconnected?.Invoke(this, new MqttClientDisconnectedEventArgs(client));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnClientSubscribedTopic(string clientId, TopicFilter topicFilter)
|
private void OnClientSubscribedTopic(string clientId, TopicFilter topicFilter)
|
||||||
{
|
{
|
||||||
ClientSubscribedTopic?.Invoke(this, new MqttClientSubscribedTopicEventArgs(clientId, topicFilter));
|
ClientSubscribedTopic?.Invoke(this, new MqttClientSubscribedTopicEventArgs(clientId, topicFilter));
|
||||||
@@ -152,7 +153,7 @@ namespace MQTTnet.Server
|
|||||||
{
|
{
|
||||||
ClientUnsubscribedTopic?.Invoke(this, new MqttClientUnsubscribedTopicEventArgs(clientId, topicFilter));
|
ClientUnsubscribedTopic?.Invoke(this, new MqttClientUnsubscribedTopicEventArgs(clientId, topicFilter));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnApplicationMessageReceived(string clientId, MqttApplicationMessage applicationMessage)
|
private void OnApplicationMessageReceived(string clientId, MqttApplicationMessage applicationMessage)
|
||||||
{
|
{
|
||||||
ApplicationMessageReceived?.Invoke(this, new MqttApplicationMessageReceivedEventArgs(clientId, applicationMessage));
|
ApplicationMessageReceived?.Invoke(this, new MqttApplicationMessageReceivedEventArgs(clientId, applicationMessage));
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ MQTTnet is a high performance .NET library for MQTT based communication. It prov
|
|||||||
* Retained messages are supported including persisting via interface methods (own implementation required)
|
* Retained messages are supported including persisting via interface methods (own implementation required)
|
||||||
* WebSockets supported (via ASP.NET Core 2.0, separate nuget)
|
* WebSockets supported (via ASP.NET Core 2.0, separate nuget)
|
||||||
* A custom message interceptor can be added which allows transforming or extending every received application message
|
* A custom message interceptor can be added which allows transforming or extending every received application message
|
||||||
|
* Validate subscriptions and deny subscribing of certain topics depending on requesting clients
|
||||||
|
|
||||||
## Supported frameworks
|
## Supported frameworks
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,66 @@
|
|||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
|
using MQTTnet.Diagnostics;
|
||||||
|
using MQTTnet.Packets;
|
||||||
|
using MQTTnet.Server;
|
||||||
|
|
||||||
|
namespace MQTTnet.Core.Tests
|
||||||
|
{
|
||||||
|
[TestClass]
|
||||||
|
public class MqttKeepAliveMonitorTests
|
||||||
|
{
|
||||||
|
[TestMethod]
|
||||||
|
public void KeepAlive_Timeout()
|
||||||
|
{
|
||||||
|
var timeoutCalledCount = 0;
|
||||||
|
|
||||||
|
var monitor = new MqttClientKeepAliveMonitor(string.Empty, delegate
|
||||||
|
{
|
||||||
|
timeoutCalledCount++;
|
||||||
|
return Task.FromResult(0);
|
||||||
|
}, new MqttNetLogger());
|
||||||
|
|
||||||
|
Assert.AreEqual(0, timeoutCalledCount);
|
||||||
|
|
||||||
|
monitor.Start(1, CancellationToken.None);
|
||||||
|
|
||||||
|
Assert.AreEqual(0, timeoutCalledCount);
|
||||||
|
|
||||||
|
Thread.Sleep(2000); // Internally the keep alive timeout is multiplied with 1.5 as per protocol specification.
|
||||||
|
|
||||||
|
Assert.AreEqual(1, timeoutCalledCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void KeepAlive_NoTimeout()
|
||||||
|
{
|
||||||
|
var timeoutCalledCount = 0;
|
||||||
|
|
||||||
|
var monitor = new MqttClientKeepAliveMonitor(string.Empty, delegate
|
||||||
|
{
|
||||||
|
timeoutCalledCount++;
|
||||||
|
return Task.FromResult(0);
|
||||||
|
}, new MqttNetLogger());
|
||||||
|
|
||||||
|
Assert.AreEqual(0, timeoutCalledCount);
|
||||||
|
|
||||||
|
monitor.Start(1, CancellationToken.None);
|
||||||
|
|
||||||
|
Assert.AreEqual(0, timeoutCalledCount);
|
||||||
|
|
||||||
|
// Simulate traffic.
|
||||||
|
Thread.Sleep(1000); // Internally the keep alive timeout is multiplied with 1.5 as per protocol specification.
|
||||||
|
monitor.PacketReceived(new MqttPublishPacket());
|
||||||
|
Thread.Sleep(1000);
|
||||||
|
monitor.PacketReceived(new MqttPublishPacket());
|
||||||
|
Thread.Sleep(1000);
|
||||||
|
|
||||||
|
Assert.AreEqual(0, timeoutCalledCount);
|
||||||
|
|
||||||
|
Thread.Sleep(2000);
|
||||||
|
|
||||||
|
Assert.AreEqual(1, timeoutCalledCount);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user