* [Server] Added support for complex client IDs.

* [Server] Fixed an issue with not correctly removed old client sessions.
* [Server] Several minor performance improvements.
* [Server] An existing client session is no longer closed if a new client connection is invalid.
* [Client] Added support for sending "CleanSession" flag.
This commit is contained in:
Christian Kratky
2017-05-05 21:34:37 +02:00
parent b3a6919ea0
commit 105abeba06
11 changed files with 204 additions and 135 deletions
+28 -24
View File
@@ -11,12 +11,12 @@ using MQTTnet.Core.Protocol;
namespace MQTTnet.Core.Server
{
public class MqttClientSession
public sealed class MqttClientSession : IDisposable
{
private readonly ConcurrentDictionary<ushort, MqttPublishPacket> _pendingIncomingPublications = new ConcurrentDictionary<ushort, MqttPublishPacket>();
private readonly MqttClientSubscriptionsManager _subscriptionsManager = new MqttClientSubscriptionsManager();
private readonly MqttOutgoingPublicationsManager _outgoingPublicationsManager;
private readonly MqttClientMessageQueue _messageQueue;
private readonly Action<MqttClientSession, MqttPublishPacket> _publishPacketReceivedCallback;
private readonly MqttServerOptions _options;
@@ -24,15 +24,17 @@ namespace MQTTnet.Core.Server
private IMqttCommunicationAdapter _adapter;
private string _identifier;
private MqttApplicationMessage _willApplicationMessage;
public MqttClientSession(MqttServerOptions options, Action<MqttClientSession, MqttPublishPacket> publishPacketReceivedCallback)
{
_options = options ?? throw new ArgumentNullException(nameof(options));
_publishPacketReceivedCallback = publishPacketReceivedCallback ?? throw new ArgumentNullException(nameof(publishPacketReceivedCallback));
_outgoingPublicationsManager = new MqttOutgoingPublicationsManager(options);
_messageQueue = new MqttClientMessageQueue(options);
}
public bool IsConnected => _adapter != null;
public async Task RunAsync(string identifier, MqttApplicationMessage willApplicationMessage, IMqttCommunicationAdapter adapter)
{
if (adapter == null) throw new ArgumentNullException(nameof(adapter));
@@ -45,7 +47,7 @@ namespace MQTTnet.Core.Server
_adapter = adapter;
_cancellationTokenSource = new CancellationTokenSource();
_outgoingPublicationsManager.Start(adapter);
_messageQueue.Start(adapter);
while (!_cancellationTokenSource.IsCancellationRequested)
{
var packet = await adapter.ReceivePacketAsync(TimeSpan.Zero);
@@ -65,8 +67,8 @@ namespace MQTTnet.Core.Server
{
_publishPacketReceivedCallback(this, _willApplicationMessage.ToPublishPacket());
}
_outgoingPublicationsManager.Stop();
_messageQueue.Stop();
_cancellationTokenSource.Cancel();
_adapter = null;
@@ -84,66 +86,68 @@ namespace MQTTnet.Core.Server
return;
}
_outgoingPublicationsManager.Enqueue(senderClientSession, publishPacket);
_messageQueue.Enqueue(senderClientSession, publishPacket);
MqttTrace.Verbose(nameof(MqttClientSession), $"Client '{_identifier}: Enqueued pending publish packet.");
}
private async Task HandleIncomingPacketAsync(MqttBasePacket packet)
public void Dispose()
{
_cancellationTokenSource?.Cancel();
_cancellationTokenSource?.Dispose();
}
private Task HandleIncomingPacketAsync(MqttBasePacket packet)
{
var subscribePacket = packet as MqttSubscribePacket;
if (subscribePacket != null)
{
await _adapter.SendPacketAsync(_subscriptionsManager.Subscribe(subscribePacket), _options.DefaultCommunicationTimeout);
return;
return _adapter.SendPacketAsync(_subscriptionsManager.Subscribe(subscribePacket), _options.DefaultCommunicationTimeout);
}
var unsubscribePacket = packet as MqttUnsubscribePacket;
if (unsubscribePacket != null)
{
await _adapter.SendPacketAsync(_subscriptionsManager.Unsubscribe(unsubscribePacket), _options.DefaultCommunicationTimeout);
return;
return _adapter.SendPacketAsync(_subscriptionsManager.Unsubscribe(unsubscribePacket), _options.DefaultCommunicationTimeout);
}
var publishPacket = packet as MqttPublishPacket;
if (publishPacket != null)
{
await HandleIncomingPublishPacketAsync(publishPacket);
return;
return HandleIncomingPublishPacketAsync(publishPacket);
}
var pubRelPacket = packet as MqttPubRelPacket;
if (pubRelPacket != null)
{
await HandleIncomingPubRelPacketAsync(pubRelPacket);
return;
return HandleIncomingPubRelPacketAsync(pubRelPacket);
}
var pubAckPacket = packet as MqttPubAckPacket;
if (pubAckPacket != null)
{
await HandleIncomingPubAckPacketAsync(pubAckPacket);
return;
return HandleIncomingPubAckPacketAsync(pubAckPacket);
}
if (packet is MqttPingReqPacket)
{
await _adapter.SendPacketAsync(new MqttPingRespPacket(), _options.DefaultCommunicationTimeout);
return;
return _adapter.SendPacketAsync(new MqttPingRespPacket(), _options.DefaultCommunicationTimeout);
}
if (packet is MqttDisconnectPacket || packet is MqttConnectPacket)
{
_cancellationTokenSource.Cancel();
return;
return Task.FromResult((object)null);
}
MqttTrace.Warning(nameof(MqttClientSession), $"Client '{_identifier}': Received not supported packet ({packet}). Closing connection.");
_cancellationTokenSource.Cancel();
return Task.FromResult((object)null);
}
private async Task HandleIncomingPubAckPacketAsync(MqttPubAckPacket pubAckPacket)
{
await Task.FromResult(0);
await Task.FromResult((object)null);
}
private async Task HandleIncomingPublishPacketAsync(MqttPublishPacket publishPacket)