private async Task ListenAsync(CancellationToken cancellationToken) { try { while (!cancellationToken.IsCancellationRequested && WebSocket.State == WebSocketState.Open) { try { while (true) { var buffer = new ArraySegment <byte>(_arrayPool.Rent(_bufferSize)); var receiveResult = await WebSocket.ReceiveAsync(buffer, cancellationToken).ConfigureAwait(false); if (receiveResult.MessageType == WebSocketMessageType.Close) { await HandleCloseMessageAsync(receiveResult); break; } if (receiveResult.MessageType != _webSocketMessageType) { CloseStatus = WebSocketCloseStatus.InvalidMessageType; CloseStatusDescription = "An unsupported message type was received"; throw new InvalidOperationException(CloseStatusDescription); } if (_jsonBuffer.Buffer.Length < receiveResult.Count + _jsonBuffer.BufferCurPos) { _jsonBuffer.IncreaseBuffer(); } Buffer.BlockCopy(buffer.Array, 0, _jsonBuffer.Buffer, _jsonBuffer.BufferCurPos, receiveResult.Count); _arrayPool.Return(buffer.Array, true); _jsonBuffer.BufferCurPos += receiveResult.Count; if (receiveResult.EndOfMessage) { break; } } byte[] jsonBytes; if (_jsonBuffer.TryExtractJsonFromBuffer(out jsonBytes)) { var envelopeJson = Encoding.UTF8.GetString(jsonBytes); if (_traceWriter != null && _traceWriter.IsEnabled) { await _traceWriter.TraceAsync(envelopeJson, DataOperation.Receive).ConfigureAwait(false); } var envelope = _envelopeSerializer.Deserialize(envelopeJson); await _receivedEnvelopeBufferBlock.SendAsync(envelope, cancellationToken); } } catch (OperationCanceledException) when(cancellationToken.IsCancellationRequested) { break; } catch (Exception ex) { } } } finally { StopListenerTask(); } }
/// <summary> /// Reads one envelope from the stream. /// </summary> /// <param name="cancellationToken"></param> /// <returns></returns> public override async Task <Envelope> ReceiveAsync(CancellationToken cancellationToken) { if (_stream == null) { throw new InvalidOperationException("The stream was not initialized. Call OpenAsync first."); } if (!_stream.CanRead) { throw new InvalidOperationException("Invalid stream state"); } await _receiveSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false); try { Envelope envelope = null; while (envelope == null) { cancellationToken.ThrowIfCancellationRequested(); envelope = await GetEnvelopeFromBufferAsync().ConfigureAwait(false); if (envelope == null && CanRead) { // The NetworkStream ReceiveAsync method doesn't supports cancellation // http://stackoverflow.com/questions/21468137/async-network-operations-never-finish // http://referencesource.microsoft.com/#mscorlib/system/io/stream.cs,421 var readTask = _stream .ReadAsync( _jsonBuffer.Buffer, _jsonBuffer.BufferCurPos, _jsonBuffer.Buffer.Length - _jsonBuffer.BufferCurPos, cancellationToken); while (!readTask.IsCompleted && CanRead) { cancellationToken.ThrowIfCancellationRequested(); await Task .WhenAny( readTask, Task.Delay(ReadTimeout, cancellationToken)) .ConfigureAwait(false); } // If is not possible to read, closes the transport and returns if (!readTask.IsCompleted) { await CloseWithTimeoutAsync().ConfigureAwait(false); break; } var read = await readTask.ConfigureAwait(false); // https://msdn.microsoft.com/en-us/library/hh193669(v=vs.110).aspx if (read == 0) { await CloseWithTimeoutAsync().ConfigureAwait(false); break; } _jsonBuffer.BufferCurPos += read; if (_jsonBuffer.BufferCurPos >= _jsonBuffer.Buffer.Length) { _jsonBuffer.IncreaseBuffer(); } } } return(envelope); } catch (BufferOverflowException) { await TraceAsync($"{nameof(RemoteEndPoint)}: {RemoteEndPoint} - BufferOverflow: {Encoding.UTF8.GetString(_jsonBuffer.Buffer)}", DataOperation.Error).ConfigureAwait(false); await CloseWithTimeoutAsync().ConfigureAwait(false); throw; } finally { _receiveSemaphore.Release(); } }
/// <summary> /// Reads one envelope from the stream. /// </summary> /// <param name="cancellationToken"></param> /// <returns></returns> public override async Task <Envelope> ReceiveAsync(CancellationToken cancellationToken) { if (_stream == null) { throw new InvalidOperationException("The stream was not initialized. Call OpenAsync first."); } if (!_stream.CanRead) { throw new InvalidOperationException("Invalid stream state"); } try { Envelope envelope = null; while (envelope == null) { cancellationToken.ThrowIfCancellationRequested(); envelope = await GetEnvelopeFromBufferAsync().ConfigureAwait(false); if (envelope == null && CanRead) { // The NetworkStream ReadAsync method doesn't supports cancellation // http://stackoverflow.com/questions/21468137/async-network-operations-never-finish // http://referencesource.microsoft.com/#mscorlib/system/io/stream.cs,421 // This is no longer true for .NET Core 3.0 // https://github.com/dotnet/corefx/pull/36516 // The problem persists only with ConnectAsync operations: // https://github.com/dotnet/corefx/issues/37118 var read = await _stream .ReadAsync( _jsonBuffer.Buffer, _jsonBuffer.BufferCurPos, _jsonBuffer.Buffer.Length - _jsonBuffer.BufferCurPos, cancellationToken) .ConfigureAwait(false); // https://msdn.microsoft.com/en-us/library/hh193669(v=vs.110).aspx if (read == 0) { await CloseWithTimeoutAsync().ConfigureAwait(false); break; } _jsonBuffer.BufferCurPos += read; if (_jsonBuffer.BufferCurPos >= _jsonBuffer.Buffer.Length) { _jsonBuffer.IncreaseBuffer(); } } } return(envelope); } catch (BufferOverflowException) { await TraceAsync($"{nameof(RemoteEndPoint)}: {RemoteEndPoint} - BufferOverflow: {Encoding.UTF8.GetString(_jsonBuffer.Buffer)}", DataOperation.Error).ConfigureAwait(false); await CloseWithTimeoutAsync().ConfigureAwait(false); throw; } }