コード例 #1
0
        public async Task RunAsync(string identifier, MqttApplicationMessage willApplicationMessage, IMqttCommunicationAdapter adapter)
        {
            if (adapter == null)
            {
                throw new ArgumentNullException(nameof(adapter));
            }

            _willApplicationMessage = willApplicationMessage;

            try
            {
                _identifier = identifier;
                _adapter    = adapter;
                _cancellationTokenSource = new CancellationTokenSource();

                _messageQueue.Start(adapter);
                while (!_cancellationTokenSource.IsCancellationRequested)
                {
                    var packet = await adapter.ReceivePacketAsync(TimeSpan.Zero);
                    await HandleIncomingPacketAsync(packet);
                }
            }
            catch (MqttCommunicationException)
            {
            }
            catch (Exception exception)
            {
                MqttTrace.Error(nameof(MqttClientSession), exception, $"Client '{_identifier}': Unhandled exception while processing client packets.");
            }
            finally
            {
                if (willApplicationMessage != null)
                {
                    _publishPacketReceivedCallback(this, _willApplicationMessage.ToPublishPacket());
                }

                _messageQueue.Stop();
                _cancellationTokenSource.Cancel();
                _adapter = null;

                MqttTrace.Information(nameof(MqttClientSession), $"Client '{_identifier}': Disconnected.");
            }
        }
コード例 #2
0
        private async Task ProcessReceivedPacketAsync(IMqttCommunicationAdapter adapter, MqttBasePacket packet)
        {
            if (packet is MqttSubscribePacket subscribePacket)
            {
                await adapter.SendPacketsAsync(_options.DefaultCommunicationTimeout, _cancellationTokenSource.Token, _subscriptionsManager.Subscribe(subscribePacket));

                EnqueueRetainedMessages(subscribePacket);
            }
            else if (packet is MqttUnsubscribePacket unsubscribePacket)
            {
                await adapter.SendPacketsAsync(_options.DefaultCommunicationTimeout, _cancellationTokenSource.Token, _subscriptionsManager.Unsubscribe(unsubscribePacket));
            }
            else if (packet is MqttPublishPacket publishPacket)
            {
                await HandleIncomingPublishPacketAsync(adapter, publishPacket);
            }
            else if (packet is MqttPubRelPacket pubRelPacket)
            {
                await HandleIncomingPubRelPacketAsync(adapter, pubRelPacket);
            }
            else if (packet is MqttPubRecPacket pubRecPacket)
            {
                await adapter.SendPacketsAsync(_options.DefaultCommunicationTimeout, _cancellationTokenSource.Token, pubRecPacket.CreateResponse <MqttPubRelPacket>());
            }
            else if (packet is MqttPubAckPacket || packet is MqttPubCompPacket)
            {
                // Discard message.
            }
            else if (packet is MqttPingReqPacket)
            {
                await adapter.SendPacketsAsync(_options.DefaultCommunicationTimeout, _cancellationTokenSource.Token, new MqttPingRespPacket());
            }
            else if (packet is MqttDisconnectPacket || packet is MqttConnectPacket)
            {
                Stop();
            }
            else
            {
                MqttNetTrace.Warning(nameof(MqttClientSession), "Client '{0}': Received not supported packet ({1}). Closing connection.", ClientId, packet);
                Stop();
            }
        }
コード例 #3
0
        public async Task ConnectAsync(MqttClientOptions options)
        {
            if (options == null)
            {
                throw new ArgumentNullException(nameof(options));
            }

            ThrowIfConnected("It is not allowed to connect with a server after the connection is established.");

            try
            {
                _options = options;
                _cancellationTokenSource = new CancellationTokenSource();
                _latestPacketIdentifier  = 0;
                _packetDispatcher.Reset();

                _adapter = _communicationChannelFactory.CreateMqttCommunicationAdapter(options);

                MqttNetTrace.Verbose(nameof(MqttClient), "Trying to connect with server.");
                await _adapter.ConnectAsync(_options.DefaultCommunicationTimeout).ConfigureAwait(false);

                MqttNetTrace.Verbose(nameof(MqttClient), "Connection with server established.");

                await SetupIncomingPacketProcessingAsync();
                await AuthenticateAsync(options.WillMessage);

                MqttNetTrace.Verbose(nameof(MqttClient), "MQTT connection with server established.");

                if (_options.KeepAlivePeriod != TimeSpan.Zero)
                {
                    StartSendKeepAliveMessages(_cancellationTokenSource.Token);
                }

                Connected?.Invoke(this, EventArgs.Empty);
            }
            catch (Exception)
            {
                await DisconnectInternalAsync().ConfigureAwait(false);

                throw;
            }
        }
コード例 #4
0
        public void Stop()
        {
            try
            {
                _cancellationTokenSource?.Cancel(false);
                _cancellationTokenSource?.Dispose();
                _cancellationTokenSource = null;

                _adapter = null;

                _logger.LogInformation("Client '{0}': Disconnected.", ClientId);
            }
            finally
            {
                if (_willMessage != null)
                {
                    _sessionsManager.DispatchApplicationMessage(this, _willMessage);
                }
            }
        }
コード例 #5
0
ファイル: MqttClientSession.cs プロジェクト: 1iveowl/MQTTnet
        public void Stop()
        {
            try
            {
                _cancellationTokenSource?.Cancel(false);
                _cancellationTokenSource?.Dispose();
                _cancellationTokenSource = null;

                _adapter = null;

                _logger.LogInformation("Client '{0}': Disconnected.", ClientId);
            }
            finally
            {
                var willMessage = _willMessage;
                if (willMessage != null)
                {
                    _willMessage = null; //clear willmessage so it is send just once
                    _sessionsManager.DispatchApplicationMessage(this, willMessage);
                }
            }
        }
コード例 #6
0
        private async Task SendPendingPublishPacketAsync(IMqttCommunicationAdapter adapter, CancellationToken cancellationToken)
        {
            MqttPublishPacket packet = null;

            try
            {
                packet = _pendingPublishPackets.Take(cancellationToken);
                await adapter.SendPacketsAsync(_options.DefaultCommunicationTimeout, cancellationToken, packet).ConfigureAwait(false);

                _logger.LogTrace("Enqueued packet sent (ClientId: {0}).", _session.ClientId);
            }
            catch (Exception exception)
            {
                if (exception is MqttCommunicationTimedOutException)
                {
                    _logger.LogWarning(new EventId(), exception, "Sending publish packet failed due to timeout (ClientId: {0}).", _session.ClientId);
                }
                else if (exception is MqttCommunicationException)
                {
                    _logger.LogWarning(new EventId(), exception, "Sending publish packet failed due to communication exception (ClientId: {0}).", _session.ClientId);
                }
                else if (exception is OperationCanceledException)
                {
                }
                else
                {
                    _logger.LogError(new EventId(), exception, "Sending publish packet failed (ClientId: {0}).", _session.ClientId);
                }

                if (packet != null && packet.QualityOfServiceLevel > MqttQualityOfServiceLevel.AtMostOnce)
                {
                    packet.Dup = true;
                    _pendingPublishPackets.Add(packet, CancellationToken.None);
                }

                _session.Stop();
            }
        }
コード例 #7
0
        private async Task HandleIncomingPublishPacketAsync(IMqttCommunicationAdapter adapter, MqttPublishPacket publishPacket)
        {
            if (publishPacket.Retain)
            {
                await _mqttClientSessionsManager.RetainedMessagesManager.HandleMessageAsync(ClientId, publishPacket);
            }

            if (publishPacket.QualityOfServiceLevel == MqttQualityOfServiceLevel.AtMostOnce)
            {
                _mqttClientSessionsManager.DispatchPublishPacket(this, publishPacket);
                return;
            }

            if (publishPacket.QualityOfServiceLevel == MqttQualityOfServiceLevel.AtLeastOnce)
            {
                _mqttClientSessionsManager.DispatchPublishPacket(this, publishPacket);
                await adapter.SendPacketsAsync(_options.DefaultCommunicationTimeout, _cancellationTokenSource.Token, new MqttPubAckPacket { PacketIdentifier = publishPacket.PacketIdentifier });

                return;
            }

            if (publishPacket.QualityOfServiceLevel == MqttQualityOfServiceLevel.ExactlyOnce)
            {
                // QoS 2 is implement as method "B" [4.3.3 QoS 2: Exactly once delivery]
                lock (_unacknowledgedPublishPackets)
                {
                    _unacknowledgedPublishPackets.Add(publishPacket.PacketIdentifier);
                }

                _mqttClientSessionsManager.DispatchPublishPacket(this, publishPacket);

                await adapter.SendPacketsAsync(_options.DefaultCommunicationTimeout, _cancellationTokenSource.Token, new MqttPubRecPacket { PacketIdentifier = publishPacket.PacketIdentifier });

                return;
            }

            throw new MqttCommunicationException("Received a not supported QoS level.");
        }
コード例 #8
0
 private async Task ReceivePacketsAsync(IMqttCommunicationAdapter adapter, CancellationToken cancellationToken)
 {
     try
     {
         while (!cancellationToken.IsCancellationRequested)
         {
             var packet = await adapter.ReceivePacketAsync(TimeSpan.Zero, cancellationToken).ConfigureAwait(false);
             await ProcessReceivedPacketAsync(adapter, packet, cancellationToken).ConfigureAwait(false);
         }
     }
     catch (OperationCanceledException)
     {
     }
     catch (MqttCommunicationException exception)
     {
         _logger.LogWarning(new EventId(), exception, "Client '{0}': Communication exception while processing client packets.", ClientId);
         await StopAsync();
     }
     catch (Exception exception)
     {
         _logger.LogError(new EventId(), exception, "Client '{0}': Unhandled exception while processing client packets.", ClientId);
         await StopAsync();
     }
 }
コード例 #9
0
 private void FireClientAcceptedEvent(IMqttCommunicationAdapter adapter)
 {
     ClientAccepted?.Invoke(adapter);
 }
コード例 #10
0
 public MqttClient(MqttClientOptions options, IMqttCommunicationAdapter adapter)
 {
     _options = options ?? throw new ArgumentNullException(nameof(options));
     _adapter = adapter ?? throw new ArgumentNullException(nameof(adapter));
 }
コード例 #11
0
        public async Task RunClientSessionAsync(IMqttCommunicationAdapter clientAdapter, CancellationToken cancellationToken)
        {
            var clientId = string.Empty;

            try
            {
                if (!(await clientAdapter.ReceivePacketAsync(_options.DefaultCommunicationTimeout, cancellationToken).ConfigureAwait(false) is MqttConnectPacket connectPacket))
                {
                    throw new MqttProtocolViolationException("The first packet from a client must be a 'CONNECT' packet [MQTT-3.1.0-1].");
                }

                clientId = connectPacket.ClientId;

                // Switch to the required protocol version before sending any response.
                clientAdapter.PacketSerializer.ProtocolVersion = connectPacket.ProtocolVersion;

                var connectReturnCode = ValidateConnection(connectPacket);
                if (connectReturnCode != MqttConnectReturnCode.ConnectionAccepted)
                {
                    await clientAdapter.SendPacketsAsync(_options.DefaultCommunicationTimeout, cancellationToken, new MqttConnAckPacket
                    {
                        ConnectReturnCode = connectReturnCode
                    }).ConfigureAwait(false);

                    return;
                }

                var clientSession = await GetOrCreateClientSessionAsync(connectPacket);

                await clientAdapter.SendPacketsAsync(_options.DefaultCommunicationTimeout, cancellationToken, new MqttConnAckPacket
                {
                    ConnectReturnCode = connectReturnCode,
                    IsSessionPresent  = clientSession.IsExistingSession
                }).ConfigureAwait(false);

                ClientConnected?.Invoke(this, new MqttClientConnectedEventArgs(new ConnectedMqttClient
                {
                    ClientId        = clientId,
                    ProtocolVersion = clientAdapter.PacketSerializer.ProtocolVersion
                }));

                using (_logger.BeginScope(clientId))
                {
                    await clientSession.Session.RunAsync(connectPacket.WillMessage, clientAdapter).ConfigureAwait(false);
                }
            }
            catch (Exception exception)
            {
                _logger.LogError(new EventId(), exception, exception.Message);
            }
            finally
            {
                try
                {
                    await clientAdapter.DisconnectAsync(_options.DefaultCommunicationTimeout).ConfigureAwait(false);
                }
                catch (Exception)
                {
                    // ignored
                }

                ClientDisconnected?.Invoke(this, new MqttClientDisconnectedEventArgs(new ConnectedMqttClient
                {
                    ClientId        = clientId,
                    ProtocolVersion = clientAdapter.PacketSerializer.ProtocolVersion
                }));
            }
        }
コード例 #12
0
 private void FireClientAcceptedEvent(IMqttCommunicationAdapter adapter)
 {
     ClientAccepted?.Invoke(this, new MqttServerAdapterClientAcceptedEventArgs(adapter));
 }
コード例 #13
0
 public TestMqttCommunicationAdapterFactory(IMqttCommunicationAdapter adapter)
 {
     _adapter = adapter;
 }
コード例 #14
0
 public void Stop()
 {
     _adapter = null;
     _cancellationTokenSource?.Cancel();
     _cancellationTokenSource = null;
 }
コード例 #15
0
 public static Task SendPacketsAsync(this IMqttCommunicationAdapter adapter, TimeSpan timeout, CancellationToken cancellationToken, params MqttBasePacket[] packets)
 {
     return(adapter.SendPacketsAsync(timeout, cancellationToken, packets));
 }
コード例 #16
0
        private async Task SendPendingPublishPacketsAsync(CancellationToken cancellationToken, IMqttCommunicationAdapter adapter)
        {
            var consumable = _pendingPublishPackets.GetConsumingEnumerable();

            while (!cancellationToken.IsCancellationRequested)
            {
                if (_pendingPublishPackets.Count == 0)
                {
                    await Task.Delay(TimeSpan.FromMilliseconds(5), cancellationToken).ConfigureAwait(false);

                    continue;
                }

                var packets = consumable.Take(_pendingPublishPackets.Count).ToList();
                try
                {
                    await adapter.SendPacketsAsync(_options.DefaultCommunicationTimeout, cancellationToken, packets).ConfigureAwait(false);
                }
                catch (MqttCommunicationException exception)
                {
                    MqttTrace.Warning(nameof(MqttClientMessageQueue), exception, "Sending publish packet failed.");
                    foreach (var publishPacket in packets)
                    {
                        publishPacket.Dup = true;
                        _pendingPublishPackets.Add(publishPacket, cancellationToken);
                    }
                }
                catch (Exception exception)
                {
                    MqttTrace.Error(nameof(MqttClientMessageQueue), exception, "Sending publish packet failed.");
                    foreach (var publishPacket in packets)
                    {
                        publishPacket.Dup = true;
                        _pendingPublishPackets.Add(publishPacket, cancellationToken);
                    }
                }
            }
        }
コード例 #17
0
 public MqttServerAdapterClientAcceptedEventArgs(IMqttCommunicationAdapter client)
 {
     Client = client ?? throw new ArgumentNullException(nameof(client));
 }
コード例 #18
0
 public MqttClientConnectedEventArgs(string identifier, IMqttCommunicationAdapter clientAdapter)
 {
     Identifier    = identifier ?? throw new ArgumentNullException(nameof(identifier));
     ClientAdapter = clientAdapter ?? throw new ArgumentNullException(nameof(clientAdapter));
 }
コード例 #19
0
 private void OnClientAccepted(IMqttCommunicationAdapter adapter)
 {
     Task.Run(() => _clientSessionsManager.RunClientSessionAsync(adapter), _cancellationTokenSource.Token);
 }