mirror of
https://github.com/dotnet/MQTTnet.git
synced 2026-11-05 05:52:56 +08:00
Add statistics of last sent packets to the _ConnectedClient_.
This commit is contained in:
@@ -33,14 +33,14 @@ namespace MQTTnet.Adapter
|
|||||||
|
|
||||||
public Task ConnectAsync(TimeSpan timeout)
|
public Task ConnectAsync(TimeSpan timeout)
|
||||||
{
|
{
|
||||||
_logger.Info<MqttChannelAdapter>("Connecting [Timeout={0}]", timeout);
|
_logger.Trace<MqttChannelAdapter>("Connecting [Timeout={0}]", timeout);
|
||||||
|
|
||||||
return ExecuteAndWrapExceptionAsync(() => _channel.ConnectAsync().TimeoutAfter(timeout));
|
return ExecuteAndWrapExceptionAsync(() => _channel.ConnectAsync().TimeoutAfter(timeout));
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task DisconnectAsync(TimeSpan timeout)
|
public Task DisconnectAsync(TimeSpan timeout)
|
||||||
{
|
{
|
||||||
_logger.Info<MqttChannelAdapter>("Disconnecting [Timeout={0}]", timeout);
|
_logger.Trace<MqttChannelAdapter>("Disconnecting [Timeout={0}]", timeout);
|
||||||
|
|
||||||
return ExecuteAndWrapExceptionAsync(() => _channel.DisconnectAsync().TimeoutAfter(timeout));
|
return ExecuteAndWrapExceptionAsync(() => _channel.DisconnectAsync().TimeoutAfter(timeout));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,8 +14,6 @@ namespace MQTTnet.Client
|
|||||||
{
|
{
|
||||||
public class MqttClient : IMqttClient
|
public class MqttClient : IMqttClient
|
||||||
{
|
{
|
||||||
private readonly HashSet<ushort> _unacknowledgedPublishPackets = new HashSet<ushort>();
|
|
||||||
|
|
||||||
private readonly IMqttClientAdapterFactory _adapterFactory;
|
private readonly IMqttClientAdapterFactory _adapterFactory;
|
||||||
private readonly MqttPacketDispatcher _packetDispatcher;
|
private readonly MqttPacketDispatcher _packetDispatcher;
|
||||||
private readonly IMqttNetLogger _logger;
|
private readonly IMqttNetLogger _logger;
|
||||||
@@ -133,7 +131,7 @@ namespace MQTTnet.Client
|
|||||||
TopicFilters = topicFilters.ToList()
|
TopicFilters = topicFilters.ToList()
|
||||||
};
|
};
|
||||||
|
|
||||||
await SendAndReceiveAsync<MqttUnsubAckPacket>(unsubscribePacket);
|
await SendAndReceiveAsync<MqttUnsubAckPacket>(unsubscribePacket).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task PublishAsync(IEnumerable<MqttApplicationMessage> applicationMessages)
|
public async Task PublishAsync(IEnumerable<MqttApplicationMessage> applicationMessages)
|
||||||
@@ -141,21 +139,21 @@ namespace MQTTnet.Client
|
|||||||
ThrowIfNotConnected();
|
ThrowIfNotConnected();
|
||||||
|
|
||||||
var publishPackets = applicationMessages.Select(m => m.ToPublishPacket());
|
var publishPackets = applicationMessages.Select(m => m.ToPublishPacket());
|
||||||
|
var packetGroups = publishPackets.GroupBy(p => p.QualityOfServiceLevel).OrderBy(g => g.Key);
|
||||||
|
|
||||||
foreach (var qosGroup in publishPackets.GroupBy(p => p.QualityOfServiceLevel))
|
foreach (var qosGroup in packetGroups)
|
||||||
{
|
{
|
||||||
var qosPackets = qosGroup.ToArray();
|
|
||||||
switch (qosGroup.Key)
|
switch (qosGroup.Key)
|
||||||
{
|
{
|
||||||
case MqttQualityOfServiceLevel.AtMostOnce:
|
case MqttQualityOfServiceLevel.AtMostOnce:
|
||||||
{
|
{
|
||||||
// No packet identifier is used for QoS 0 [3.3.2.2 Packet Identifier]
|
// No packet identifier is used for QoS 0 [3.3.2.2 Packet Identifier]
|
||||||
await _adapter.SendPacketsAsync(_options.CommunicationTimeout, _cancellationTokenSource.Token, qosPackets).ConfigureAwait(false);
|
await _adapter.SendPacketsAsync(_options.CommunicationTimeout, _cancellationTokenSource.Token, qosGroup).ConfigureAwait(false);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case MqttQualityOfServiceLevel.AtLeastOnce:
|
case MqttQualityOfServiceLevel.AtLeastOnce:
|
||||||
{
|
{
|
||||||
foreach (var publishPacket in qosPackets)
|
foreach (var publishPacket in qosGroup)
|
||||||
{
|
{
|
||||||
publishPacket.PacketIdentifier = GetNewPacketIdentifier();
|
publishPacket.PacketIdentifier = GetNewPacketIdentifier();
|
||||||
await SendAndReceiveAsync<MqttPubAckPacket>(publishPacket).ConfigureAwait(false);
|
await SendAndReceiveAsync<MqttPubAckPacket>(publishPacket).ConfigureAwait(false);
|
||||||
@@ -165,7 +163,7 @@ namespace MQTTnet.Client
|
|||||||
}
|
}
|
||||||
case MqttQualityOfServiceLevel.ExactlyOnce:
|
case MqttQualityOfServiceLevel.ExactlyOnce:
|
||||||
{
|
{
|
||||||
foreach (var publishPacket in qosPackets)
|
foreach (var publishPacket in qosGroup)
|
||||||
{
|
{
|
||||||
publishPacket.PacketIdentifier = GetNewPacketIdentifier();
|
publishPacket.PacketIdentifier = GetNewPacketIdentifier();
|
||||||
var pubRecPacket = await SendAndReceiveAsync<MqttPubRecPacket>(publishPacket).ConfigureAwait(false);
|
var pubRecPacket = await SendAndReceiveAsync<MqttPubRecPacket>(publishPacket).ConfigureAwait(false);
|
||||||
@@ -249,28 +247,28 @@ namespace MQTTnet.Client
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
_logger.Info<MqttClient>("Received <<< {0}", packet);
|
_logger.Info<MqttClient>("Received <<< {0}", packet);
|
||||||
|
|
||||||
|
if (packet is MqttPublishPacket publishPacket)
|
||||||
|
{
|
||||||
|
await ProcessReceivedPublishPacketAsync(publishPacket).ConfigureAwait(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (packet is MqttPingReqPacket)
|
if (packet is MqttPingReqPacket)
|
||||||
{
|
{
|
||||||
await SendAsync(new MqttPingRespPacket());
|
await SendAsync(new MqttPingRespPacket()).ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (packet is MqttDisconnectPacket)
|
if (packet is MqttDisconnectPacket)
|
||||||
{
|
{
|
||||||
await DisconnectAsync();
|
await DisconnectAsync().ConfigureAwait(false);
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (packet is MqttPublishPacket publishPacket)
|
|
||||||
{
|
|
||||||
await ProcessReceivedPublishPacket(publishPacket);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (packet is MqttPubRelPacket pubRelPacket)
|
if (packet is MqttPubRelPacket pubRelPacket)
|
||||||
{
|
{
|
||||||
await ProcessReceivedPubRelPacket(pubRelPacket);
|
await ProcessReceivedPubRelPacket(pubRelPacket).ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -295,32 +293,25 @@ namespace MQTTnet.Client
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task ProcessReceivedPublishPacket(MqttPublishPacket publishPacket)
|
private Task ProcessReceivedPublishPacketAsync(MqttPublishPacket publishPacket)
|
||||||
{
|
{
|
||||||
if (publishPacket.QualityOfServiceLevel == MqttQualityOfServiceLevel.AtMostOnce)
|
if (publishPacket.QualityOfServiceLevel == MqttQualityOfServiceLevel.AtMostOnce)
|
||||||
{
|
{
|
||||||
FireApplicationMessageReceivedEvent(publishPacket);
|
FireApplicationMessageReceivedEvent(publishPacket);
|
||||||
return;
|
return Task.FromResult(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (publishPacket.QualityOfServiceLevel == MqttQualityOfServiceLevel.AtLeastOnce)
|
if (publishPacket.QualityOfServiceLevel == MqttQualityOfServiceLevel.AtLeastOnce)
|
||||||
{
|
{
|
||||||
FireApplicationMessageReceivedEvent(publishPacket);
|
FireApplicationMessageReceivedEvent(publishPacket);
|
||||||
await SendAsync(new MqttPubAckPacket { PacketIdentifier = publishPacket.PacketIdentifier });
|
return SendAsync(new MqttPubAckPacket { PacketIdentifier = publishPacket.PacketIdentifier });
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (publishPacket.QualityOfServiceLevel == MqttQualityOfServiceLevel.ExactlyOnce)
|
if (publishPacket.QualityOfServiceLevel == MqttQualityOfServiceLevel.ExactlyOnce)
|
||||||
{
|
{
|
||||||
// QoS 2 is implement as method "B" [4.3.3 QoS 2: Exactly once delivery]
|
// QoS 2 is implement as method "B" [4.3.3 QoS 2: Exactly once delivery]
|
||||||
lock (_unacknowledgedPublishPackets)
|
|
||||||
{
|
|
||||||
_unacknowledgedPublishPackets.Add(publishPacket.PacketIdentifier);
|
|
||||||
}
|
|
||||||
|
|
||||||
FireApplicationMessageReceivedEvent(publishPacket);
|
FireApplicationMessageReceivedEvent(publishPacket);
|
||||||
await SendAsync(new MqttPubRecPacket { PacketIdentifier = publishPacket.PacketIdentifier });
|
return SendAsync(new MqttPubRecPacket { PacketIdentifier = publishPacket.PacketIdentifier });
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new MqttCommunicationException("Received a not supported QoS level.");
|
throw new MqttCommunicationException("Received a not supported QoS level.");
|
||||||
@@ -328,11 +319,6 @@ namespace MQTTnet.Client
|
|||||||
|
|
||||||
private Task ProcessReceivedPubRelPacket(MqttPubRelPacket pubRelPacket)
|
private Task ProcessReceivedPubRelPacket(MqttPubRelPacket pubRelPacket)
|
||||||
{
|
{
|
||||||
lock (_unacknowledgedPublishPackets)
|
|
||||||
{
|
|
||||||
_unacknowledgedPublishPackets.Remove(pubRelPacket.PacketIdentifier);
|
|
||||||
}
|
|
||||||
|
|
||||||
return SendAsync(pubRelPacket.CreateResponse<MqttPubCompPacket>());
|
return SendAsync(pubRelPacket.CreateResponse<MqttPubCompPacket>());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -454,7 +440,7 @@ namespace MQTTnet.Client
|
|||||||
{
|
{
|
||||||
#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
|
#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
|
||||||
Task.Run(
|
Task.Run(
|
||||||
() => ProcessReceivedPacketAsync(packet),
|
async () => await ProcessReceivedPacketAsync(packet).ConfigureAwait(false),
|
||||||
cancellationToken).ConfigureAwait(false);
|
cancellationToken).ConfigureAwait(false);
|
||||||
#pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
|
#pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
|
||||||
}
|
}
|
||||||
@@ -465,7 +451,7 @@ namespace MQTTnet.Client
|
|||||||
|
|
||||||
#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
|
#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
|
||||||
Task.Run(
|
Task.Run(
|
||||||
async () => await ReceivePacketsAsync(cancellationToken),
|
async () => await ReceivePacketsAsync(cancellationToken).ConfigureAwait(false),
|
||||||
cancellationToken).ConfigureAwait(false);
|
cancellationToken).ConfigureAwait(false);
|
||||||
#pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
|
#pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
|
||||||
|
|
||||||
@@ -479,7 +465,7 @@ namespace MQTTnet.Client
|
|||||||
{
|
{
|
||||||
#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
|
#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
|
||||||
Task.Run(
|
Task.Run(
|
||||||
async () => await SendKeepAliveMessagesAsync(cancellationToken),
|
async () => await SendKeepAliveMessagesAsync(cancellationToken).ConfigureAwait(false),
|
||||||
cancellationToken).ConfigureAwait(false);
|
cancellationToken).ConfigureAwait(false);
|
||||||
#pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
|
#pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ namespace MQTTnet.Diagnostics
|
|||||||
{
|
{
|
||||||
_logId = logId;
|
_logId = logId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public event EventHandler<MqttNetLogMessagePublishedEventArgs> LogMessagePublished;
|
public event EventHandler<MqttNetLogMessagePublishedEventArgs> LogMessagePublished;
|
||||||
|
|
||||||
public void Trace<TSource>(string message, params object[] parameters)
|
public void Trace<TSource>(string message, params object[] parameters)
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ namespace MQTTnet.Implementations
|
|||||||
_defaultEndpointSocket.Bind(new IPEndPoint(IPAddress.Any, options.GetDefaultEndpointPort()));
|
_defaultEndpointSocket.Bind(new IPEndPoint(IPAddress.Any, options.GetDefaultEndpointPort()));
|
||||||
_defaultEndpointSocket.Listen(options.ConnectionBacklog);
|
_defaultEndpointSocket.Listen(options.ConnectionBacklog);
|
||||||
|
|
||||||
Task.Run(() => AcceptDefaultEndpointConnectionsAsync(_cancellationTokenSource.Token), _cancellationTokenSource.Token);
|
Task.Run(async () => await AcceptDefaultEndpointConnectionsAsync(_cancellationTokenSource.Token).ConfigureAwait(false), _cancellationTokenSource.Token).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (options.TlsEndpointOptions.IsEnabled)
|
if (options.TlsEndpointOptions.IsEnabled)
|
||||||
@@ -62,7 +62,7 @@ namespace MQTTnet.Implementations
|
|||||||
_tlsEndpointSocket.Bind(new IPEndPoint(IPAddress.Any, options.GetTlsEndpointPort()));
|
_tlsEndpointSocket.Bind(new IPEndPoint(IPAddress.Any, options.GetTlsEndpointPort()));
|
||||||
_tlsEndpointSocket.Listen(options.ConnectionBacklog);
|
_tlsEndpointSocket.Listen(options.ConnectionBacklog);
|
||||||
|
|
||||||
Task.Run(() => AcceptTlsEndpointConnectionsAsync(_cancellationTokenSource.Token), _cancellationTokenSource.Token);
|
Task.Run(async () => await AcceptTlsEndpointConnectionsAsync(_cancellationTokenSource.Token).ConfigureAwait(false), _cancellationTokenSource.Token).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Task.FromResult(0);
|
return Task.FromResult(0);
|
||||||
@@ -102,13 +102,29 @@ namespace MQTTnet.Implementations
|
|||||||
#else
|
#else
|
||||||
var clientSocket = await _defaultEndpointSocket.AcceptAsync().ConfigureAwait(false);
|
var clientSocket = await _defaultEndpointSocket.AcceptAsync().ConfigureAwait(false);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
var clientAdapter = new MqttChannelAdapter(new MqttTcpChannel(clientSocket, null), new MqttPacketSerializer(), _logger);
|
var clientAdapter = new MqttChannelAdapter(new MqttTcpChannel(clientSocket, null), new MqttPacketSerializer(), _logger);
|
||||||
ClientAccepted?.Invoke(this, new MqttServerAdapterClientAcceptedEventArgs(clientAdapter));
|
ClientAccepted?.Invoke(this, new MqttServerAdapterClientAcceptedEventArgs(clientAdapter));
|
||||||
}
|
}
|
||||||
|
catch (ObjectDisposedException)
|
||||||
|
{
|
||||||
|
// It can happen that the listener socket is accessed after the cancellation token is already set and the listener socket is disposed.
|
||||||
|
}
|
||||||
|
catch (SocketException exception)
|
||||||
|
{
|
||||||
|
if (exception.SocketErrorCode == SocketError.OperationAborted)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_logger.Error<MqttServerAdapter>(exception, "Error while accepting connection at default endpoint.");
|
||||||
|
}
|
||||||
catch (Exception exception)
|
catch (Exception exception)
|
||||||
{
|
{
|
||||||
_logger.Error<MqttServerAdapter>(exception, "Error while accepting connection at default endpoint.");
|
_logger.Error<MqttServerAdapter>(exception, "Error while accepting connection at default endpoint.");
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
//excessive CPU consumed if in endless loop of socket errors
|
//excessive CPU consumed if in endless loop of socket errors
|
||||||
await Task.Delay(TimeSpan.FromSeconds(1), cancellationToken).ConfigureAwait(false);
|
await Task.Delay(TimeSpan.FromSeconds(1), cancellationToken).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
@@ -133,10 +149,25 @@ namespace MQTTnet.Implementations
|
|||||||
var clientAdapter = new MqttChannelAdapter(new MqttTcpChannel(clientSocket, sslStream), new MqttPacketSerializer(), _logger);
|
var clientAdapter = new MqttChannelAdapter(new MqttTcpChannel(clientSocket, sslStream), new MqttPacketSerializer(), _logger);
|
||||||
ClientAccepted?.Invoke(this, new MqttServerAdapterClientAcceptedEventArgs(clientAdapter));
|
ClientAccepted?.Invoke(this, new MqttServerAdapterClientAcceptedEventArgs(clientAdapter));
|
||||||
}
|
}
|
||||||
|
catch (ObjectDisposedException)
|
||||||
|
{
|
||||||
|
// It can happen that the listener socket is accessed after the cancellation token is already set and the listener socket is disposed.
|
||||||
|
}
|
||||||
|
catch (SocketException exception)
|
||||||
|
{
|
||||||
|
if (exception.SocketErrorCode == SocketError.OperationAborted)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_logger.Error<MqttServerAdapter>(exception, "Error while accepting connection at default endpoint.");
|
||||||
|
}
|
||||||
catch (Exception exception)
|
catch (Exception exception)
|
||||||
{
|
{
|
||||||
_logger.Error<MqttServerAdapter>(exception, "Error while accepting connection at TLS endpoint.");
|
_logger.Error<MqttServerAdapter>(exception, "Error while accepting connection at TLS endpoint.");
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
//excessive CPU consumed if in endless loop of socket errors
|
//excessive CPU consumed if in endless loop of socket errors
|
||||||
await Task.Delay(TimeSpan.FromSeconds(1), cancellationToken).ConfigureAwait(false);
|
await Task.Delay(TimeSpan.FromSeconds(1), cancellationToken).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,8 +9,8 @@ namespace MQTTnet.Server
|
|||||||
|
|
||||||
public MqttProtocolVersion ProtocolVersion { get; set; }
|
public MqttProtocolVersion ProtocolVersion { get; set; }
|
||||||
|
|
||||||
public TimeSpan LastPacketReceivedDuration { get; set; }
|
public TimeSpan LastPacketReceived { get; set; }
|
||||||
|
|
||||||
public TimeSpan LastNonKeepAlivePacketReceivedDuration{ get; set; }
|
public TimeSpan LastNonKeepAlivePacketReceived { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Diagnostics;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using MQTTnet.Adapter;
|
using MQTTnet.Adapter;
|
||||||
@@ -13,6 +14,9 @@ namespace MQTTnet.Server
|
|||||||
{
|
{
|
||||||
public sealed class MqttClientSession
|
public sealed class MqttClientSession
|
||||||
{
|
{
|
||||||
|
private readonly Stopwatch _lastPacketReceivedTracker = new Stopwatch();
|
||||||
|
private readonly Stopwatch _lastNonKeepAlivePacketReceivedTracker = new Stopwatch();
|
||||||
|
|
||||||
private readonly MqttClientSubscriptionsManager _subscriptionsManager;
|
private readonly MqttClientSubscriptionsManager _subscriptionsManager;
|
||||||
private readonly MqttClientSessionsManager _sessionsManager;
|
private readonly MqttClientSessionsManager _sessionsManager;
|
||||||
private readonly MqttClientPendingMessagesQueue _pendingMessagesQueue;
|
private readonly MqttClientPendingMessagesQueue _pendingMessagesQueue;
|
||||||
@@ -44,6 +48,10 @@ namespace MQTTnet.Server
|
|||||||
|
|
||||||
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(MqttApplicationMessage willMessage, IMqttChannelAdapter adapter)
|
public async Task RunAsync(MqttApplicationMessage willMessage, IMqttChannelAdapter adapter)
|
||||||
@@ -52,6 +60,9 @@ namespace MQTTnet.Server
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
_lastPacketReceivedTracker.Restart();
|
||||||
|
_lastNonKeepAlivePacketReceivedTracker.Restart();
|
||||||
|
|
||||||
var cancellationTokenSource = new CancellationTokenSource();
|
var cancellationTokenSource = new CancellationTokenSource();
|
||||||
|
|
||||||
_willMessage = willMessage;
|
_willMessage = willMessage;
|
||||||
@@ -78,6 +89,11 @@ namespace MQTTnet.Server
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
if (_cancellationTokenSource == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
_cancellationTokenSource?.Cancel(false);
|
_cancellationTokenSource?.Cancel(false);
|
||||||
_cancellationTokenSource?.Dispose();
|
_cancellationTokenSource?.Dispose();
|
||||||
_cancellationTokenSource = null;
|
_cancellationTokenSource = null;
|
||||||
@@ -143,6 +159,13 @@ namespace MQTTnet.Server
|
|||||||
|
|
||||||
private Task ProcessReceivedPacketAsync(IMqttChannelAdapter adapter, MqttBasePacket packet, CancellationToken cancellationToken)
|
private Task ProcessReceivedPacketAsync(IMqttChannelAdapter adapter, MqttBasePacket packet, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
|
_lastPacketReceivedTracker.Restart();
|
||||||
|
|
||||||
|
if (!(packet is MqttPingReqPacket))
|
||||||
|
{
|
||||||
|
_lastNonKeepAlivePacketReceivedTracker.Restart();
|
||||||
|
}
|
||||||
|
|
||||||
if (packet is MqttPublishPacket publishPacket)
|
if (packet is MqttPublishPacket publishPacket)
|
||||||
{
|
{
|
||||||
return HandleIncomingPublishPacketAsync(adapter, publishPacket, cancellationToken);
|
return HandleIncomingPublishPacketAsync(adapter, publishPacket, cancellationToken);
|
||||||
@@ -185,7 +208,7 @@ namespace MQTTnet.Server
|
|||||||
}
|
}
|
||||||
|
|
||||||
_logger.Warning<MqttClientSession>("Client '{0}': Received not supported packet ({1}). Closing connection.", ClientId, packet);
|
_logger.Warning<MqttClientSession>("Client '{0}': Received not supported packet ({1}). Closing connection.", ClientId, packet);
|
||||||
return StopAsync();
|
return StopAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task HandleIncomingSubscribePacketAsync(IMqttChannelAdapter adapter, MqttSubscribePacket subscribePacket, CancellationToken cancellationToken)
|
private async Task HandleIncomingSubscribePacketAsync(IMqttChannelAdapter adapter, MqttSubscribePacket subscribePacket, CancellationToken cancellationToken)
|
||||||
@@ -211,7 +234,7 @@ namespace MQTTnet.Server
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task HandleIncomingPublishPacketAsync(IMqttChannelAdapter adapter, MqttPublishPacket publishPacket, CancellationToken cancellationToken)
|
private Task HandleIncomingPublishPacketAsync(IMqttChannelAdapter adapter, MqttPublishPacket publishPacket, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var applicationMessage = publishPacket.ToApplicationMessage();
|
var applicationMessage = publishPacket.ToApplicationMessage();
|
||||||
|
|
||||||
@@ -219,36 +242,44 @@ namespace MQTTnet.Server
|
|||||||
{
|
{
|
||||||
case MqttQualityOfServiceLevel.AtMostOnce:
|
case MqttQualityOfServiceLevel.AtMostOnce:
|
||||||
{
|
{
|
||||||
await _sessionsManager.DispatchApplicationMessageAsync(this, applicationMessage).ConfigureAwait(false);
|
return _sessionsManager.DispatchApplicationMessageAsync(this, applicationMessage);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
case MqttQualityOfServiceLevel.AtLeastOnce:
|
case MqttQualityOfServiceLevel.AtLeastOnce:
|
||||||
{
|
{
|
||||||
await _sessionsManager.DispatchApplicationMessageAsync(this, applicationMessage).ConfigureAwait(false);
|
return HandleIncomingPublishPacketWithQoS1(adapter, applicationMessage, publishPacket, cancellationToken);
|
||||||
|
|
||||||
await adapter.SendPacketsAsync(_options.DefaultCommunicationTimeout, cancellationToken,
|
|
||||||
new MqttPubAckPacket { PacketIdentifier = publishPacket.PacketIdentifier }).ConfigureAwait(false);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
case MqttQualityOfServiceLevel.ExactlyOnce:
|
case MqttQualityOfServiceLevel.ExactlyOnce:
|
||||||
{
|
{
|
||||||
// QoS 2 is implement as method "B" [4.3.3 QoS 2: Exactly once delivery]
|
return HandleIncomingPublishPacketWithQoS2(adapter, applicationMessage, publishPacket, cancellationToken);
|
||||||
await _sessionsManager.DispatchApplicationMessageAsync(this, applicationMessage).ConfigureAwait(false);
|
|
||||||
|
|
||||||
await adapter.SendPacketsAsync(_options.DefaultCommunicationTimeout, cancellationToken,
|
|
||||||
new MqttPubRecPacket { PacketIdentifier = publishPacket.PacketIdentifier }).ConfigureAwait(false);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
throw new MqttCommunicationException("Received a not supported QoS level.");
|
{
|
||||||
|
throw new MqttCommunicationException("Received a not supported QoS level.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task HandleIncomingPublishPacketWithQoS1(IMqttChannelAdapter adapter, MqttApplicationMessage applicationMessage, MqttPublishPacket publishPacket, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
await _sessionsManager.DispatchApplicationMessageAsync(this, applicationMessage).ConfigureAwait(false);
|
||||||
|
|
||||||
|
var response = new MqttPubAckPacket { PacketIdentifier = publishPacket.PacketIdentifier };
|
||||||
|
await adapter.SendPacketsAsync(_options.DefaultCommunicationTimeout, cancellationToken, response).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task HandleIncomingPublishPacketWithQoS2(IMqttChannelAdapter adapter, MqttApplicationMessage applicationMessage, MqttPublishPacket publishPacket, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
// QoS 2 is implement as method "B" [4.3.3 QoS 2: Exactly once delivery]
|
||||||
|
await _sessionsManager.DispatchApplicationMessageAsync(this, applicationMessage).ConfigureAwait(false);
|
||||||
|
|
||||||
|
var response = new MqttPubRecPacket { PacketIdentifier = publishPacket.PacketIdentifier };
|
||||||
|
await adapter.SendPacketsAsync(_options.DefaultCommunicationTimeout, cancellationToken, response).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
private Task HandleIncomingPubRelPacketAsync(IMqttChannelAdapter adapter, MqttPubRelPacket pubRelPacket, CancellationToken cancellationToken)
|
private Task HandleIncomingPubRelPacketAsync(IMqttChannelAdapter adapter, MqttPubRelPacket pubRelPacket, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
return adapter.SendPacketsAsync(_options.DefaultCommunicationTimeout, cancellationToken, new MqttPubCompPacket { PacketIdentifier = pubRelPacket.PacketIdentifier });
|
var response = new MqttPubCompPacket { PacketIdentifier = pubRelPacket.PacketIdentifier };
|
||||||
|
return adapter.SendPacketsAsync(_options.DefaultCommunicationTimeout, cancellationToken, response);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -120,11 +120,12 @@ namespace MQTTnet.Server
|
|||||||
await _sessionsSemaphore.WaitAsync().ConfigureAwait(false);
|
await _sessionsSemaphore.WaitAsync().ConfigureAwait(false);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var now = DateTime.UtcNow;
|
|
||||||
return _sessions.Where(s => s.Value.IsConnected).Select(s => new ConnectedMqttClient
|
return _sessions.Where(s => s.Value.IsConnected).Select(s => new ConnectedMqttClient
|
||||||
{
|
{
|
||||||
ClientId = s.Value.ClientId,
|
ClientId = s.Value.ClientId,
|
||||||
ProtocolVersion = s.Value.ProtocolVersion ?? MqttProtocolVersion.V311
|
ProtocolVersion = s.Value.ProtocolVersion ?? MqttProtocolVersion.V311,
|
||||||
|
LastPacketReceived = s.Value.LastPacketReceived,
|
||||||
|
LastNonKeepAlivePacketReceived = s.Value.LastNonKeepAlivePacketReceived
|
||||||
}).ToList();
|
}).ToList();
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ namespace MQTTnet.TestApp.NetCore
|
|||||||
|
|
||||||
Thread.Sleep(Timeout.Infinite);
|
Thread.Sleep(Timeout.Infinite);
|
||||||
}
|
}
|
||||||
|
|
||||||
// This code is used at the Wiki on GitHub!
|
// This code is used at the Wiki on GitHub!
|
||||||
// ReSharper disable once UnusedMember.Local
|
// ReSharper disable once UnusedMember.Local
|
||||||
private static async void WikiCode()
|
private static async void WikiCode()
|
||||||
@@ -71,6 +71,26 @@ namespace MQTTnet.TestApp.NetCore
|
|||||||
var factory = new MqttFactory();
|
var factory = new MqttFactory();
|
||||||
var client = factory.CreateMqttClient();
|
var client = factory.CreateMqttClient();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// Write all trace messages to the console window.
|
||||||
|
MqttNetGlobalLogger.LogMessagePublished += (s, e) =>
|
||||||
|
{
|
||||||
|
var trace = $">> [{e.TraceMessage.Timestamp:O}] [{e.TraceMessage.ThreadId}] [{e.TraceMessage.Source}] [{e.TraceMessage.Level}]: {e.TraceMessage.Message}";
|
||||||
|
if (e.TraceMessage.Exception != null)
|
||||||
|
{
|
||||||
|
trace += Environment.NewLine + e.TraceMessage.Exception.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
Console.WriteLine(trace);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// Use a custom log ID for the logger.
|
||||||
|
var factory = new MqttFactory();
|
||||||
|
var mqttClient = factory.CreateMqttClient(new MqttNetLogger("MyCustomId"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -106,4 +126,4 @@ namespace MQTTnet.TestApp.NetCore
|
|||||||
return Task.FromResult(retainedMessages);
|
return Task.FromResult(retainedMessages);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user