mirror of
https://github.com/dotnet/MQTTnet.git
synced 2026-10-20 19:58:57 +08:00
Process client messages in worker thread (extend options)
This commit is contained in:
@@ -17,12 +17,12 @@ namespace MQTTnet.AspNetCore
|
|||||||
{
|
{
|
||||||
string subprotocol = null;
|
string subprotocol = null;
|
||||||
|
|
||||||
if (context.Request.Headers.TryGetValue("Sec-WebSocket-Protocol", out var requestedSubProtocolValues)
|
if (context.Request.Headers.TryGetValue("Sec-WebSocket-Protocol", out var requestedSubProtocolValues))
|
||||||
&& requestedSubProtocolValues.Count > 0
|
|
||||||
&& requestedSubProtocolValues.Any(v => v.ToLower() == "mqtt")
|
|
||||||
)
|
|
||||||
{
|
{
|
||||||
subprotocol = "mqtt";
|
// Order the protocols to also match "mqtt", "mqttv-3.1", "mqttv-3.11" etc.
|
||||||
|
subprotocol = requestedSubProtocolValues
|
||||||
|
.OrderByDescending(p => p.Length)
|
||||||
|
.FirstOrDefault(p => p.ToLower().StartsWith("mqtt"));
|
||||||
}
|
}
|
||||||
|
|
||||||
var adapter = app.ApplicationServices.GetRequiredService<MqttWebSocketServerAdapter>();
|
var adapter = app.ApplicationServices.GetRequiredService<MqttWebSocketServerAdapter>();
|
||||||
|
|||||||
@@ -6,17 +6,16 @@ namespace MQTTnet.Client
|
|||||||
public interface IMqttClientOptions
|
public interface IMqttClientOptions
|
||||||
{
|
{
|
||||||
string ClientId { get; }
|
string ClientId { get; }
|
||||||
|
|
||||||
IMqttClientCredentials Credentials { get; }
|
|
||||||
bool CleanSession { get; }
|
bool CleanSession { get; }
|
||||||
MqttApplicationMessage WillMessage { get; }
|
IMqttClientCredentials Credentials { get; }
|
||||||
|
MqttProtocolVersion ProtocolVersion { get; }
|
||||||
|
IMqttClientChannelOptions ChannelOptions { get; }
|
||||||
|
|
||||||
TimeSpan CommunicationTimeout { get; }
|
TimeSpan CommunicationTimeout { get; }
|
||||||
TimeSpan KeepAlivePeriod { get; }
|
TimeSpan KeepAlivePeriod { get; }
|
||||||
TimeSpan? KeepAliveSendInterval { get; }
|
TimeSpan? KeepAliveSendInterval { get; }
|
||||||
|
MqttReceivedApplicationMessageProcessingMode ReceivedApplicationMessageProcessingMode { get; }
|
||||||
|
|
||||||
MqttProtocolVersion ProtocolVersion { get; }
|
MqttApplicationMessage WillMessage { get; }
|
||||||
|
|
||||||
IMqttClientChannelOptions ChannelOptions { get; }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -23,7 +23,6 @@ namespace MQTTnet.Client
|
|||||||
private readonly IMqttNetLogger _logger;
|
private readonly IMqttNetLogger _logger;
|
||||||
|
|
||||||
private IMqttClientOptions _options;
|
private IMqttClientOptions _options;
|
||||||
private bool _isReceivingPackets;
|
|
||||||
private CancellationTokenSource _cancellationTokenSource;
|
private CancellationTokenSource _cancellationTokenSource;
|
||||||
private Task _packetReceiverTask;
|
private Task _packetReceiverTask;
|
||||||
private Task _keepAliveMessageSenderTask;
|
private Task _keepAliveMessageSenderTask;
|
||||||
@@ -63,16 +62,16 @@ namespace MQTTnet.Client
|
|||||||
await _adapter.ConnectAsync(_options.CommunicationTimeout).ConfigureAwait(false);
|
await _adapter.ConnectAsync(_options.CommunicationTimeout).ConfigureAwait(false);
|
||||||
_logger.Verbose<MqttClient>("Connection with server established.");
|
_logger.Verbose<MqttClient>("Connection with server established.");
|
||||||
|
|
||||||
await StartReceivingPacketsAsync().ConfigureAwait(false);
|
StartReceivingPackets(_cancellationTokenSource.Token);
|
||||||
|
|
||||||
var connectResponse = await AuthenticateAsync(options.WillMessage).ConfigureAwait(false);
|
var connectResponse = await AuthenticateAsync(options.WillMessage, _cancellationTokenSource.Token).ConfigureAwait(false);
|
||||||
_logger.Verbose<MqttClient>("MQTT connection with server established.");
|
_logger.Verbose<MqttClient>("MQTT connection with server established.");
|
||||||
|
|
||||||
_sendTracker.Restart();
|
_sendTracker.Restart();
|
||||||
|
|
||||||
if (_options.KeepAlivePeriod != TimeSpan.Zero)
|
if (_options.KeepAlivePeriod != TimeSpan.Zero)
|
||||||
{
|
{
|
||||||
StartSendingKeepAliveMessages();
|
StartSendingKeepAliveMessages(_cancellationTokenSource.Token);
|
||||||
}
|
}
|
||||||
|
|
||||||
IsConnected = true;
|
IsConnected = true;
|
||||||
@@ -101,7 +100,7 @@ namespace MQTTnet.Client
|
|||||||
{
|
{
|
||||||
if (!_cancellationTokenSource.IsCancellationRequested)
|
if (!_cancellationTokenSource.IsCancellationRequested)
|
||||||
{
|
{
|
||||||
await SendAsync(new MqttDisconnectPacket()).ConfigureAwait(false);
|
await SendAsync(new MqttDisconnectPacket(), _cancellationTokenSource.Token).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
@@ -122,7 +121,7 @@ namespace MQTTnet.Client
|
|||||||
TopicFilters = topicFilters.ToList()
|
TopicFilters = topicFilters.ToList()
|
||||||
};
|
};
|
||||||
|
|
||||||
var response = await SendAndReceiveAsync<MqttSubAckPacket>(subscribePacket).ConfigureAwait(false);
|
var response = await SendAndReceiveAsync<MqttSubAckPacket>(subscribePacket, _cancellationTokenSource.Token).ConfigureAwait(false);
|
||||||
|
|
||||||
if (response.SubscribeReturnCodes.Count != subscribePacket.TopicFilters.Count)
|
if (response.SubscribeReturnCodes.Count != subscribePacket.TopicFilters.Count)
|
||||||
{
|
{
|
||||||
@@ -144,7 +143,7 @@ namespace MQTTnet.Client
|
|||||||
TopicFilters = topicFilters.ToList()
|
TopicFilters = topicFilters.ToList()
|
||||||
};
|
};
|
||||||
|
|
||||||
await SendAndReceiveAsync<MqttUnsubAckPacket>(unsubscribePacket).ConfigureAwait(false);
|
await SendAndReceiveAsync<MqttUnsubAckPacket>(unsubscribePacket, _cancellationTokenSource.Token).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task PublishAsync(IEnumerable<MqttApplicationMessage> applicationMessages)
|
public async Task PublishAsync(IEnumerable<MqttApplicationMessage> applicationMessages)
|
||||||
@@ -161,7 +160,7 @@ namespace MQTTnet.Client
|
|||||||
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 SendAsync(qosGroup.Cast<MqttBasePacket>().ToArray()).ConfigureAwait(false);
|
await SendAsync(qosGroup, _cancellationTokenSource.Token).ConfigureAwait(false);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case MqttQualityOfServiceLevel.AtLeastOnce:
|
case MqttQualityOfServiceLevel.AtLeastOnce:
|
||||||
@@ -169,7 +168,7 @@ namespace MQTTnet.Client
|
|||||||
foreach (var publishPacket in qosGroup)
|
foreach (var publishPacket in qosGroup)
|
||||||
{
|
{
|
||||||
publishPacket.PacketIdentifier = _packetIdentifierProvider.GetNewPacketIdentifier();
|
publishPacket.PacketIdentifier = _packetIdentifierProvider.GetNewPacketIdentifier();
|
||||||
await SendAndReceiveAsync<MqttPubAckPacket>(publishPacket).ConfigureAwait(false);
|
await SendAndReceiveAsync<MqttPubAckPacket>(publishPacket, _cancellationTokenSource.Token).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@@ -180,13 +179,13 @@ namespace MQTTnet.Client
|
|||||||
{
|
{
|
||||||
publishPacket.PacketIdentifier = _packetIdentifierProvider.GetNewPacketIdentifier();
|
publishPacket.PacketIdentifier = _packetIdentifierProvider.GetNewPacketIdentifier();
|
||||||
|
|
||||||
var pubRecPacket = await SendAndReceiveAsync<MqttPubRecPacket>(publishPacket).ConfigureAwait(false);
|
var pubRecPacket = await SendAndReceiveAsync<MqttPubRecPacket>(publishPacket, _cancellationTokenSource.Token).ConfigureAwait(false);
|
||||||
var pubRelPacket = new MqttPubRelPacket
|
var pubRelPacket = new MqttPubRelPacket
|
||||||
{
|
{
|
||||||
PacketIdentifier = pubRecPacket.PacketIdentifier
|
PacketIdentifier = pubRecPacket.PacketIdentifier
|
||||||
};
|
};
|
||||||
|
|
||||||
await SendAndReceiveAsync<MqttPubCompPacket>(pubRelPacket).ConfigureAwait(false);
|
await SendAndReceiveAsync<MqttPubCompPacket>(pubRelPacket, _cancellationTokenSource.Token).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@@ -207,7 +206,7 @@ namespace MQTTnet.Client
|
|||||||
_adapter?.Dispose();
|
_adapter?.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<MqttConnAckPacket> AuthenticateAsync(MqttApplicationMessage willApplicationMessage)
|
private async Task<MqttConnAckPacket> AuthenticateAsync(MqttApplicationMessage willApplicationMessage, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var connectPacket = new MqttConnectPacket
|
var connectPacket = new MqttConnectPacket
|
||||||
{
|
{
|
||||||
@@ -219,7 +218,7 @@ namespace MQTTnet.Client
|
|||||||
WillMessage = willApplicationMessage
|
WillMessage = willApplicationMessage
|
||||||
};
|
};
|
||||||
|
|
||||||
var response = await SendAndReceiveAsync<MqttConnAckPacket>(connectPacket).ConfigureAwait(false);
|
var response = await SendAndReceiveAsync<MqttConnAckPacket>(connectPacket, _cancellationTokenSource.Token).ConfigureAwait(false);
|
||||||
if (response.ConnectReturnCode != MqttConnectReturnCode.ConnectionAccepted)
|
if (response.ConnectReturnCode != MqttConnectReturnCode.ConnectionAccepted)
|
||||||
{
|
{
|
||||||
throw new MqttConnectingFailedException(response.ConnectReturnCode);
|
throw new MqttConnectingFailedException(response.ConnectReturnCode);
|
||||||
@@ -264,21 +263,19 @@ namespace MQTTnet.Client
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (_packetReceiverTask != null && _packetReceiverTask != sender)
|
await WaitForTaskAsync(_packetReceiverTask, sender).ConfigureAwait(false);
|
||||||
{
|
await WaitForTaskAsync(_keepAliveMessageSenderTask, sender).ConfigureAwait(false);
|
||||||
_packetReceiverTask.Wait();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_keepAliveMessageSenderTask != null && _keepAliveMessageSenderTask != sender)
|
if (_keepAliveMessageSenderTask != null && _keepAliveMessageSenderTask != sender)
|
||||||
{
|
{
|
||||||
_keepAliveMessageSenderTask.Wait();
|
await _keepAliveMessageSenderTask.ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_adapter != null)
|
if (_adapter != null)
|
||||||
{
|
{
|
||||||
await _adapter.DisconnectAsync(_options.CommunicationTimeout).ConfigureAwait(false);
|
await _adapter.DisconnectAsync(_options.CommunicationTimeout).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
_logger.Verbose<MqttClient>("Disconnected from adapter.");
|
_logger.Verbose<MqttClient>("Disconnected from adapter.");
|
||||||
}
|
}
|
||||||
catch (Exception adapterException)
|
catch (Exception adapterException)
|
||||||
@@ -297,101 +294,19 @@ namespace MQTTnet.Client
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task ProcessReceivedPacketAsync(MqttBasePacket packet)
|
private Task SendAsync(MqttBasePacket packet, CancellationToken cancellationToken)
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (packet is MqttPublishPacket publishPacket)
|
|
||||||
{
|
|
||||||
await ProcessReceivedPublishPacketAsync(publishPacket).ConfigureAwait(false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (packet is MqttPingReqPacket)
|
|
||||||
{
|
|
||||||
await SendAsync(new MqttPingRespPacket()).ConfigureAwait(false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (packet is MqttDisconnectPacket)
|
|
||||||
{
|
|
||||||
await DisconnectAsync().ConfigureAwait(false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (packet is MqttPubRelPacket pubRelPacket)
|
|
||||||
{
|
|
||||||
await ProcessReceivedPubRelPacket(pubRelPacket).ConfigureAwait(false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
_packetDispatcher.Dispatch(packet);
|
|
||||||
}
|
|
||||||
catch (Exception exception)
|
|
||||||
{
|
|
||||||
_logger.Error<MqttClient>(exception, "Unhandled exception while processing received packet.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void FireApplicationMessageReceivedEvent(MqttPublishPacket publishPacket)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var applicationMessage = publishPacket.ToApplicationMessage();
|
|
||||||
ApplicationMessageReceived?.Invoke(this, new MqttApplicationMessageReceivedEventArgs(_options.ClientId, applicationMessage));
|
|
||||||
}
|
|
||||||
catch (Exception exception)
|
|
||||||
{
|
|
||||||
_logger.Error<MqttClient>(exception, "Unhandled exception while handling application message.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private Task ProcessReceivedPublishPacketAsync(MqttPublishPacket publishPacket)
|
|
||||||
{
|
|
||||||
if (_cancellationTokenSource.IsCancellationRequested)
|
|
||||||
{
|
|
||||||
return Task.FromResult(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (publishPacket.QualityOfServiceLevel == MqttQualityOfServiceLevel.AtMostOnce)
|
|
||||||
{
|
|
||||||
FireApplicationMessageReceivedEvent(publishPacket);
|
|
||||||
return Task.FromResult(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (publishPacket.QualityOfServiceLevel == MqttQualityOfServiceLevel.AtLeastOnce)
|
|
||||||
{
|
|
||||||
FireApplicationMessageReceivedEvent(publishPacket);
|
|
||||||
return SendAsync(new MqttPubAckPacket { PacketIdentifier = publishPacket.PacketIdentifier });
|
|
||||||
}
|
|
||||||
|
|
||||||
if (publishPacket.QualityOfServiceLevel == MqttQualityOfServiceLevel.ExactlyOnce)
|
|
||||||
{
|
|
||||||
// QoS 2 is implement as method "B" [4.3.3 QoS 2: Exactly once delivery]
|
|
||||||
FireApplicationMessageReceivedEvent(publishPacket);
|
|
||||||
return SendAsync(new MqttPubRecPacket { PacketIdentifier = publishPacket.PacketIdentifier });
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new MqttCommunicationException("Received a not supported QoS level.");
|
|
||||||
}
|
|
||||||
|
|
||||||
private Task ProcessReceivedPubRelPacket(MqttPubRelPacket pubRelPacket)
|
|
||||||
{
|
|
||||||
var response = new MqttPubCompPacket
|
|
||||||
{
|
|
||||||
PacketIdentifier = pubRelPacket.PacketIdentifier
|
|
||||||
};
|
|
||||||
|
|
||||||
return SendAsync(response);
|
|
||||||
}
|
|
||||||
|
|
||||||
private Task SendAsync(params MqttBasePacket[] packets)
|
|
||||||
{
|
{
|
||||||
_sendTracker.Restart();
|
_sendTracker.Restart();
|
||||||
return _adapter.SendPacketsAsync(_options.CommunicationTimeout, _cancellationTokenSource.Token, packets);
|
return _adapter.SendPacketsAsync(_options.CommunicationTimeout, cancellationToken, new[] { packet });
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<TResponsePacket> SendAndReceiveAsync<TResponsePacket>(MqttBasePacket requestPacket) where TResponsePacket : MqttBasePacket
|
private Task SendAsync(IEnumerable<MqttBasePacket> packets, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
_sendTracker.Restart();
|
||||||
|
return _adapter.SendPacketsAsync(_options.CommunicationTimeout, cancellationToken, packets);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<TResponsePacket> SendAndReceiveAsync<TResponsePacket>(MqttBasePacket requestPacket, CancellationToken cancellationToken) where TResponsePacket : MqttBasePacket
|
||||||
{
|
{
|
||||||
ushort? identifier = null;
|
ushort? identifier = null;
|
||||||
if (requestPacket is IMqttPacketWithIdentifier requestPacketWithIdentifier)
|
if (requestPacket is IMqttPacketWithIdentifier requestPacketWithIdentifier)
|
||||||
@@ -400,18 +315,18 @@ namespace MQTTnet.Client
|
|||||||
}
|
}
|
||||||
|
|
||||||
var packetAwaiter = _packetDispatcher.WaitForPacketAsync(typeof(TResponsePacket), identifier, _options.CommunicationTimeout);
|
var packetAwaiter = _packetDispatcher.WaitForPacketAsync(typeof(TResponsePacket), identifier, _options.CommunicationTimeout);
|
||||||
await SendAsync(requestPacket).ConfigureAwait(false);
|
await SendAsync(requestPacket, cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
return (TResponsePacket)await packetAwaiter.ConfigureAwait(false);
|
return (TResponsePacket)await packetAwaiter.ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task SendKeepAliveMessagesAsync()
|
private async Task SendKeepAliveMessagesAsync(CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
_logger.Verbose<MqttClient>("Start sending keep alive packets.");
|
_logger.Verbose<MqttClient>("Start sending keep alive packets.");
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
while (!_cancellationTokenSource.Token.IsCancellationRequested)
|
while (!cancellationToken.IsCancellationRequested)
|
||||||
{
|
{
|
||||||
var keepAliveSendInterval = TimeSpan.FromSeconds(_options.KeepAlivePeriod.TotalSeconds * 0.75);
|
var keepAliveSendInterval = TimeSpan.FromSeconds(_options.KeepAlivePeriod.TotalSeconds * 0.75);
|
||||||
if (_options.KeepAliveSendInterval.HasValue)
|
if (_options.KeepAliveSendInterval.HasValue)
|
||||||
@@ -421,10 +336,10 @@ namespace MQTTnet.Client
|
|||||||
|
|
||||||
if (_sendTracker.Elapsed > keepAliveSendInterval)
|
if (_sendTracker.Elapsed > keepAliveSendInterval)
|
||||||
{
|
{
|
||||||
await SendAndReceiveAsync<MqttPingRespPacket>(new MqttPingReqPacket()).ConfigureAwait(false);
|
await SendAndReceiveAsync<MqttPingRespPacket>(new MqttPingReqPacket(), cancellationToken).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
await Task.Delay(keepAliveSendInterval, _cancellationTokenSource.Token).ConfigureAwait(false);
|
await Task.Delay(keepAliveSendInterval, cancellationToken).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception exception)
|
catch (Exception exception)
|
||||||
@@ -440,7 +355,7 @@ namespace MQTTnet.Client
|
|||||||
{
|
{
|
||||||
_logger.Error<MqttClient>(exception, "Unhandled exception while sending/receiving keep alive packets.");
|
_logger.Error<MqttClient>(exception, "Unhandled exception while sending/receiving keep alive packets.");
|
||||||
}
|
}
|
||||||
|
|
||||||
await DisconnectInternalAsync(_keepAliveMessageSenderTask, exception).ConfigureAwait(false);
|
await DisconnectInternalAsync(_keepAliveMessageSenderTask, exception).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
@@ -449,24 +364,34 @@ namespace MQTTnet.Client
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task ReceivePacketsAsync()
|
private async Task ReceivePacketsAsync(CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
_logger.Verbose<MqttClient>("Start receiving packets.");
|
_logger.Verbose<MqttClient>("Start receiving packets.");
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
while (!_cancellationTokenSource.Token.IsCancellationRequested)
|
while (!cancellationToken.IsCancellationRequested)
|
||||||
{
|
{
|
||||||
_isReceivingPackets = true;
|
var packet = await _adapter.ReceivePacketAsync(TimeSpan.Zero, cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
var packet = await _adapter.ReceivePacketAsync(TimeSpan.Zero, _cancellationTokenSource.Token).ConfigureAwait(false);
|
if (cancellationToken.IsCancellationRequested)
|
||||||
|
|
||||||
if (_cancellationTokenSource.Token.IsCancellationRequested)
|
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
StartProcessReceivedPacket(packet);
|
if (packet == null)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_options.ReceivedApplicationMessageProcessingMode == MqttReceivedApplicationMessageProcessingMode.SingleThread)
|
||||||
|
{
|
||||||
|
await ProcessReceivedPacketAsync(packet, cancellationToken).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
else if (_options.ReceivedApplicationMessageProcessingMode == MqttReceivedApplicationMessageProcessingMode.DedicatedThread)
|
||||||
|
{
|
||||||
|
StartProcessReceivedPacketAsync(packet, cancellationToken);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception exception)
|
catch (Exception exception)
|
||||||
@@ -491,26 +416,125 @@ namespace MQTTnet.Client
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void StartProcessReceivedPacket(MqttBasePacket packet)
|
private async Task ProcessReceivedPacketAsync(MqttBasePacket packet, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
Task.Run(() => ProcessReceivedPacketAsync(packet), _cancellationTokenSource.Token);
|
try
|
||||||
}
|
|
||||||
|
|
||||||
private async Task StartReceivingPacketsAsync()
|
|
||||||
{
|
|
||||||
_isReceivingPackets = false;
|
|
||||||
|
|
||||||
_packetReceiverTask = Task.Run(ReceivePacketsAsync, _cancellationTokenSource.Token);
|
|
||||||
|
|
||||||
while (!_isReceivingPackets && !_cancellationTokenSource.Token.IsCancellationRequested)
|
|
||||||
{
|
{
|
||||||
await Task.Delay(TimeSpan.FromMilliseconds(100), _cancellationTokenSource.Token).ConfigureAwait(false);
|
if (packet is MqttPublishPacket publishPacket)
|
||||||
|
{
|
||||||
|
await ProcessReceivedPublishPacketAsync(publishPacket, cancellationToken).ConfigureAwait(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (packet is MqttPingReqPacket)
|
||||||
|
{
|
||||||
|
await SendAsync(new MqttPingRespPacket(), cancellationToken).ConfigureAwait(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (packet is MqttDisconnectPacket)
|
||||||
|
{
|
||||||
|
await DisconnectAsync().ConfigureAwait(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (packet is MqttPubRelPacket pubRelPacket)
|
||||||
|
{
|
||||||
|
await ProcessReceivedPubRelPacket(pubRelPacket, cancellationToken).ConfigureAwait(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_packetDispatcher.Dispatch(packet);
|
||||||
|
}
|
||||||
|
catch (Exception exception)
|
||||||
|
{
|
||||||
|
_logger.Error<MqttClient>(exception, "Unhandled exception while processing received packet.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void StartSendingKeepAliveMessages()
|
private Task ProcessReceivedPublishPacketAsync(MqttPublishPacket publishPacket, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
_keepAliveMessageSenderTask = Task.Run(SendKeepAliveMessagesAsync, _cancellationTokenSource.Token);
|
if (publishPacket.QualityOfServiceLevel == MqttQualityOfServiceLevel.AtMostOnce)
|
||||||
|
{
|
||||||
|
FireApplicationMessageReceivedEvent(publishPacket);
|
||||||
|
return Task.FromResult(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (publishPacket.QualityOfServiceLevel == MqttQualityOfServiceLevel.AtLeastOnce)
|
||||||
|
{
|
||||||
|
FireApplicationMessageReceivedEvent(publishPacket);
|
||||||
|
return SendAsync(new MqttPubAckPacket { PacketIdentifier = publishPacket.PacketIdentifier }, cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (publishPacket.QualityOfServiceLevel == MqttQualityOfServiceLevel.ExactlyOnce)
|
||||||
|
{
|
||||||
|
// QoS 2 is implement as method "B" [4.3.3 QoS 2: Exactly once delivery]
|
||||||
|
FireApplicationMessageReceivedEvent(publishPacket);
|
||||||
|
return SendAsync(new MqttPubRecPacket { PacketIdentifier = publishPacket.PacketIdentifier }, cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new MqttCommunicationException("Received a not supported QoS level.");
|
||||||
|
}
|
||||||
|
|
||||||
|
private Task ProcessReceivedPubRelPacket(MqttPubRelPacket pubRelPacket, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var response = new MqttPubCompPacket
|
||||||
|
{
|
||||||
|
PacketIdentifier = pubRelPacket.PacketIdentifier
|
||||||
|
};
|
||||||
|
|
||||||
|
return SendAsync(response, cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void StartReceivingPackets(CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
_packetReceiverTask = Task.Run(() => ReceivePacketsAsync(cancellationToken), cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void StartSendingKeepAliveMessages(CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
_keepAliveMessageSenderTask = Task.Run(() => SendKeepAliveMessagesAsync(cancellationToken), cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void StartProcessReceivedPacketAsync(MqttBasePacket packet, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
|
||||||
|
Task.Run(() => ProcessReceivedPacketAsync(packet, cancellationToken), cancellationToken);
|
||||||
|
#pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
|
||||||
|
}
|
||||||
|
|
||||||
|
private void FireApplicationMessageReceivedEvent(MqttPublishPacket publishPacket)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var applicationMessage = publishPacket.ToApplicationMessage();
|
||||||
|
ApplicationMessageReceived?.Invoke(this, new MqttApplicationMessageReceivedEventArgs(_options.ClientId, applicationMessage));
|
||||||
|
}
|
||||||
|
catch (Exception exception)
|
||||||
|
{
|
||||||
|
_logger.Error<MqttClient>(exception, "Unhandled exception while handling application message.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static async Task WaitForTaskAsync(Task task, Task sender)
|
||||||
|
{
|
||||||
|
if (task == sender)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (task.IsCanceled || task.IsCompleted || task.IsFaulted)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await task.ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
catch (TaskCanceledException)
|
||||||
|
{
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -5,22 +5,17 @@ namespace MQTTnet.Client
|
|||||||
{
|
{
|
||||||
public class MqttClientOptions : IMqttClientOptions
|
public class MqttClientOptions : IMqttClientOptions
|
||||||
{
|
{
|
||||||
public MqttApplicationMessage WillMessage { get; set; }
|
|
||||||
|
|
||||||
public string ClientId { get; set; } = Guid.NewGuid().ToString("N");
|
public string ClientId { get; set; } = Guid.NewGuid().ToString("N");
|
||||||
|
|
||||||
public bool CleanSession { get; set; } = true;
|
public bool CleanSession { get; set; } = true;
|
||||||
|
|
||||||
public IMqttClientCredentials Credentials { get; set; } = new MqttClientCredentials();
|
public IMqttClientCredentials Credentials { get; set; } = new MqttClientCredentials();
|
||||||
|
public MqttProtocolVersion ProtocolVersion { get; set; } = MqttProtocolVersion.V311;
|
||||||
public TimeSpan KeepAlivePeriod { get; set; } = TimeSpan.FromSeconds(15);
|
public IMqttClientChannelOptions ChannelOptions { get; set; }
|
||||||
|
|
||||||
public TimeSpan? KeepAliveSendInterval { get; set; }
|
|
||||||
|
|
||||||
public TimeSpan CommunicationTimeout { get; set; } = TimeSpan.FromSeconds(10);
|
public TimeSpan CommunicationTimeout { get; set; } = TimeSpan.FromSeconds(10);
|
||||||
|
public TimeSpan KeepAlivePeriod { get; set; } = TimeSpan.FromSeconds(15);
|
||||||
|
public TimeSpan? KeepAliveSendInterval { get; set; }
|
||||||
|
public MqttReceivedApplicationMessageProcessingMode ReceivedApplicationMessageProcessingMode { get; set; } = MqttReceivedApplicationMessageProcessingMode.SingleThread;
|
||||||
|
|
||||||
public MqttProtocolVersion ProtocolVersion { get; set; } = MqttProtocolVersion.V311;
|
public MqttApplicationMessage WillMessage { get; set; }
|
||||||
|
|
||||||
public IMqttClientChannelOptions ChannelOptions { get; set; }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -108,6 +108,13 @@ namespace MQTTnet.Client
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public MqttClientOptionsBuilder WithReceivedApplicationMessageProcessingMode(
|
||||||
|
MqttReceivedApplicationMessageProcessingMode mode)
|
||||||
|
{
|
||||||
|
_options.ReceivedApplicationMessageProcessingMode = mode;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
public IMqttClientOptions Build()
|
public IMqttClientOptions Build()
|
||||||
{
|
{
|
||||||
if (_tlsOptions != null)
|
if (_tlsOptions != null)
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
namespace MQTTnet.Client
|
||||||
|
{
|
||||||
|
public enum MqttReceivedApplicationMessageProcessingMode
|
||||||
|
{
|
||||||
|
SingleThread,
|
||||||
|
DedicatedThread
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user