示例#1
0
文件: MqttClient.cs 项目: pangfd/SAEA
        private async Task <TResponsePacket> SendAndReceiveAsync <TResponsePacket>(MqttBasePacket requestPacket, CancellationToken cancellationToken) where TResponsePacket : MqttBasePacket
        {
            cancellationToken.ThrowIfCancellationRequested();

            _sendTracker.Restart();

            ushort identifier = 0;

            if (requestPacket is IMqttPacketWithIdentifier packetWithIdentifier && packetWithIdentifier.PacketIdentifier.HasValue)
            {
                identifier = packetWithIdentifier.PacketIdentifier.Value;
            }

            var packetAwaiter = _packetDispatcher.AddPacketAwaiter <TResponsePacket>(identifier);

            try
            {
                await _adapter.SendPacketAsync(requestPacket, cancellationToken).ConfigureAwait(false);

                var respone = await Common.TaskExtensions.TimeoutAfterAsync(ct => packetAwaiter.Task, Options.CommunicationTimeout, cancellationToken).ConfigureAwait(false);

                return((TResponsePacket)respone);
            }
            catch (MqttCommunicationTimedOutException)
            {
                _logger.Warning(null, "Timeout while waiting for packet of type '{0}'.", typeof(TResponsePacket).Namespace);
                throw;
            }
            finally
            {
                _packetDispatcher.RemovePacketAwaiter <TResponsePacket>(identifier);
            }
        }
示例#2
0
        private async Task <TResponsePacket> SendAndReceiveAsync <TResponsePacket>(Packet requestPacket, CancellationToken cancellationToken) where TResponsePacket : Packet
        {
            cancellationToken.ThrowIfCancellationRequested();

            ushort identifier = 0;

            if (requestPacket is PacketWithId packetWithId)
            {
                identifier = packetWithId.PacketId;
            }

            var awaiter = _packetDispatcher.AddPacketAwaiter <TResponsePacket>(identifier);

            try
            {
                await _clientChannel.WriteAndFlushAsync(requestPacket);

                //var respone = await Extensions.TaskExtensions.TimeoutAfterAsync(ct => packetAwaiter.Task, _options.Timeout, cancellationToken);
                //return (TResponsePacket)respone;

                using (var timeoutCts = new CancellationTokenSource(_options.Timeout))
                    using (var linkedCts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, timeoutCts.Token))
                    {
                        linkedCts.Token.Register(() =>
                        {
                            if (!awaiter.Task.IsCompleted && !awaiter.Task.IsFaulted && !awaiter.Task.IsCanceled)
                            {
                                awaiter.TrySetCanceled();
                            }
                        });

                        try
                        {
                            var result = await awaiter.Task.ConfigureAwait(false);

                            timeoutCts.Cancel(false);
                            return((TResponsePacket)result);
                        }
                        catch (OperationCanceledException exception)
                        {
                            if (timeoutCts.IsCancellationRequested && !cancellationToken.IsCancellationRequested)
                            {
                                throw new MqttTimeoutException(exception);
                            }
                            else
                            {
                                throw;
                            }
                        }
                    }
            }
            catch (Exception)
            {
                throw;
            }
            finally
            {
                _packetDispatcher.RemovePacketAwaiter <TResponsePacket>(identifier);
            }
        }
示例#3
0
        private async Task SendPendingPacketsAsync(CancellationToken cancellationToken)
        {
            MqttQueuedApplicationMessage queuedApplicationMessage = null;
            MqttPublishPacket            publishPacket            = null;

            try
            {
                while (!cancellationToken.IsCancellationRequested)
                {
                    queuedApplicationMessage = await Session.ApplicationMessagesQueue.TakeAsync(cancellationToken).ConfigureAwait(false);

                    if (queuedApplicationMessage == null)
                    {
                        return;
                    }

                    if (cancellationToken.IsCancellationRequested)
                    {
                        return;
                    }

                    publishPacket = _dataConverter.CreatePublishPacket(queuedApplicationMessage.ApplicationMessage);
                    publishPacket.QualityOfServiceLevel = queuedApplicationMessage.QualityOfServiceLevel;

                    // Set the retain flag to true according to [MQTT-3.3.1-8] and [MQTT-3.3.1-9].
                    publishPacket.Retain = queuedApplicationMessage.IsRetainedMessage;

                    if (publishPacket.QualityOfServiceLevel > 0)
                    {
                        publishPacket.PacketIdentifier = _packetIdentifierProvider.GetNextPacketIdentifier();
                    }

                    if (_serverOptions.ClientMessageQueueInterceptor != null)
                    {
                        var context = new MqttClientMessageQueueInterceptorContext(
                            queuedApplicationMessage.SenderClientId,
                            ClientId,
                            queuedApplicationMessage.ApplicationMessage);

                        if (_serverOptions.ClientMessageQueueInterceptor != null)
                        {
                            await _serverOptions.ClientMessageQueueInterceptor.InterceptClientMessageQueueEnqueueAsync(context).ConfigureAwait(false);
                        }

                        if (!context.AcceptEnqueue || context.ApplicationMessage == null)
                        {
                            return;
                        }

                        publishPacket.Topic   = context.ApplicationMessage.Topic;
                        publishPacket.Payload = context.ApplicationMessage.Payload;
                        publishPacket.QualityOfServiceLevel = context.ApplicationMessage.QualityOfServiceLevel;
                    }

                    if (publishPacket.QualityOfServiceLevel == MqttQualityOfServiceLevel.AtMostOnce)
                    {
                        await SendAsync(publishPacket).ConfigureAwait(false);
                    }
                    else if (publishPacket.QualityOfServiceLevel == MqttQualityOfServiceLevel.AtLeastOnce)
                    {
                        var awaiter = _packetDispatcher.AddPacketAwaiter <MqttPubAckPacket>(publishPacket.PacketIdentifier);
                        await SendAsync(publishPacket).ConfigureAwait(false);

                        await awaiter.WaitOneAsync(_serverOptions.DefaultCommunicationTimeout).ConfigureAwait(false);
                    }
                    else if (publishPacket.QualityOfServiceLevel == MqttQualityOfServiceLevel.ExactlyOnce)
                    {
                        using (var awaiter1 = _packetDispatcher.AddPacketAwaiter <MqttPubRecPacket>(publishPacket.PacketIdentifier))
                            using (var awaiter2 = _packetDispatcher.AddPacketAwaiter <MqttPubCompPacket>(publishPacket.PacketIdentifier))
                            {
                                await SendAsync(publishPacket).ConfigureAwait(false);

                                await awaiter1.WaitOneAsync(_serverOptions.DefaultCommunicationTimeout).ConfigureAwait(false);

                                await SendAsync(new MqttPubRelPacket { PacketIdentifier = publishPacket.PacketIdentifier }).ConfigureAwait(false);

                                await awaiter2.WaitOneAsync(_serverOptions.DefaultCommunicationTimeout).ConfigureAwait(false);
                            }
                    }

                    _logger.Verbose("Queued application message sent (ClientId: {0}).", ClientId);

                    // TODO:
                    //Interlocked.Increment(ref _sentPacketsCount);
                }
            }
            catch (Exception exception)
            {
                if (exception is MqttCommunicationTimedOutException)
                {
                    _logger.Warning(exception, "Sending publish packet failed: Timeout (ClientId: {0}).", ClientId);
                }
                else if (exception is MqttCommunicationException)
                {
                    _logger.Warning(exception, "Sending publish packet failed: Communication exception (ClientId: {0}).", ClientId);
                }
                else if (exception is OperationCanceledException && _cancellationToken.Token.IsCancellationRequested)
                {
                    // The cancellation was triggered externally.
                }
                else
                {
                    _logger.Error(exception, "Sending publish packet failed (ClientId: {0}).", ClientId);
                }

                if (publishPacket?.QualityOfServiceLevel > MqttQualityOfServiceLevel.AtMostOnce)
                {
                    queuedApplicationMessage.IsDuplicate = true;

                    Session.ApplicationMessagesQueue.Enqueue(queuedApplicationMessage);
                }

                if (!_cancellationToken.Token.IsCancellationRequested)
                {
                    await StopAsync().ConfigureAwait(false);
                }
            }
        }