public async Task <MqttBasePacket> ReceivePacketAsync(TimeSpan timeout, CancellationToken cancellationToken) { var input = Connection.Transport.Input; try { while (!cancellationToken.IsCancellationRequested) { ReadResult readResult; var readTask = input.ReadAsync(cancellationToken); if (readTask.IsCompleted) { readResult = readTask.Result; } else { readResult = await readTask.ConfigureAwait(false); } var buffer = readResult.Buffer; var consumed = buffer.Start; var observed = buffer.Start; try { if (!buffer.IsEmpty) { if (PacketSerializer.TryDeserialize(buffer, out var packet, out consumed, out observed)) { return(packet); } else { // we did receive something but the message is not yet complete ReadingPacketStarted?.Invoke(this, EventArgs.Empty); } } else if (readResult.IsCompleted) { throw new MqttCommunicationException("Connection Aborted"); } } finally { // The buffer was sliced up to where it was consumed, so we can just advance to the start. // We mark examined as buffer.End so that if we didn't receive a full frame, we'll wait for more data // before yielding the read again. input.AdvanceTo(consumed, observed); } }
private async Task <ReceivedMqttPacket> ReceiveAsync(CancellationToken cancellationToken) { var fixedHeader = await MqttPacketReader.ReadFixedHeaderAsync(_channel, _fixedHeaderBuffer, _singleByteBuffer, cancellationToken).ConfigureAwait(false); try { ReadingPacketStarted?.Invoke(this, EventArgs.Empty); if (fixedHeader.RemainingLength == 0) { return(new ReceivedMqttPacket(fixedHeader.Flags, null)); } var body = new byte[fixedHeader.RemainingLength]; var bodyOffset = 0; var chunkSize = Math.Min(ReadBufferSize, fixedHeader.RemainingLength); do { var bytesLeft = body.Length - bodyOffset; if (chunkSize > bytesLeft) { chunkSize = bytesLeft; } #if WINDOWS_UWP var readBytes = await _channel.ReadAsync(body, bodyOffset, chunkSize, cancellationToken).ConfigureAwait(false); #else // async/await is not used to avoid the overhead of context switches. We assume that the reamining data // has been sent from the sender directly after the initial bytes. //var readBytes = _channel.ReadAsync(body, bodyOffset, chunkSize, cancellationToken).ConfigureAwait(false).GetAwaiter().GetResult(); var readBytes = AsyncContext.Run(async() => await _channel.ReadAsync(body, bodyOffset, chunkSize, cancellationToken).ConfigureAwait(false)); #endif cancellationToken.ThrowIfCancellationRequested(); ExceptionHelper.ThrowIfGracefulSocketClose(readBytes); bodyOffset += readBytes; } while (bodyOffset < body.Length); return(new ReceivedMqttPacket(fixedHeader.Flags, new MqttPacketBodyReader(body, 0, body.Length))); } finally { ReadingPacketCompleted?.Invoke(this, EventArgs.Empty); } }
private async Task <MqttReceivedPacket> ReceiveAsync(CancellationToken cancellationToken) { var fixedHeader = await MqttPacketReader.ReadFixedHeaderAsync(_channel, _fixedHeaderBuffer, _singleByteBuffer, cancellationToken).ConfigureAwait(false); try { ReadingPacketStarted?.Invoke(this, EventArgs.Empty); if (fixedHeader.RemainingLength == 0) { return(new MqttReceivedPacket(fixedHeader.Flags, null)); } var body = new byte[fixedHeader.RemainingLength]; var bodyOffset = 0; var chunkSize = Math.Min(ReadBufferSize, fixedHeader.RemainingLength); do { var bytesLeft = body.Length - bodyOffset; if (chunkSize > bytesLeft) { chunkSize = bytesLeft; } //async/await不用于避免上下文切换的开销。我们假设扩孔数据已从发件人直接发送到初始字节之后。 var readBytes = _channel.ReadAsync(body, bodyOffset, chunkSize, cancellationToken).ConfigureAwait(false).GetAwaiter().GetResult(); cancellationToken.ThrowIfCancellationRequested(); ExceptionHelper.ThrowIfGracefulSocketClose(readBytes); bodyOffset += readBytes; } while (bodyOffset < body.Length); return(new MqttReceivedPacket(fixedHeader.Flags, new MqttPacketBodyReader(body, 0, body.Length))); } finally { ReadingPacketCompleted?.Invoke(this, EventArgs.Empty); } }