public void FlushAsyncAwaitableCompletesWhenReaderAdvancesUnderLow() { PipeWriter writableBuffer = _pipe.Writer.WriteEmpty(PauseWriterThreshold); ValueTask <FlushResult> flushAsync = writableBuffer.FlushAsync(); Assert.False(flushAsync.IsCompleted); ReadResult result = _pipe.Reader.ReadAsync().GetAwaiter().GetResult(); SequencePosition consumed = result.Buffer.GetPosition(33); _pipe.Reader.AdvanceTo(consumed, consumed); Assert.True(flushAsync.IsCompleted); FlushResult flushResult = flushAsync.GetAwaiter().GetResult(); Assert.False(flushResult.IsCompleted); }
//写入循环 private async Task FillPipeAsync(Socket socket, PipeWriter writer) { //数据流量比较大,用8k作为buffer const int minimumBufferSize = 1024 * 8; while (running) { try { //从writer中,获得一段不少于指定大小的内存空间 Memory <byte> memory = writer.GetMemory(minimumBufferSize); await socket.ReceiveAsync(memory, SocketFlags.None); //将内存空间变成ArraySegment,提供给socket使用 if (!MemoryMarshal.TryGetArray((ReadOnlyMemory <byte>)memory, out ArraySegment <byte> arraySegment)) { throw new InvalidOperationException("Buffer backed by array was expected"); } //接受数据 int bytesRead = await SocketTaskExtensions.ReceiveAsync(socket, arraySegment, SocketFlags.None); if (bytesRead == 0) { break; } //一次接受完毕,数据已经在pipe中,告诉pipe已经给它写了多少数据。 writer.Advance(bytesRead); } catch { break; } // 提示reader可以进行读取数据,reader可以继续执行readAsync()方法 FlushResult result = await writer.FlushAsync(); if (result.IsCompleted) { break; } } // 告诉pipe完事了 writer.Complete(); }
public async Task WriteLargeDataBinary(int length) { var data = new byte[length]; new Random(length).NextBytes(data); PipeWriter output = Pipe.Writer; output.Write(data); await output.FlushAsync(); ReadResult result = await Pipe.Reader.ReadAsync(); ReadOnlySequence <byte> input = result.Buffer; Assert.Equal(data, input.ToArray()); Pipe.Reader.AdvanceTo(input.End); }
public void FlushAsyncReturnsIsCancelOnCancelPendingFlushBeforeGetResult() { PipeWriter writableBuffer = Pipe.Writer.WriteEmpty(MaximumSizeHigh); PipeAwaiter <FlushResult> awaitable = writableBuffer.FlushAsync(); Assert.False(awaitable.IsCompleted); awaitable.OnCompleted(() => { }); Pipe.Reader.AdvanceTo(Pipe.Reader.ReadAsync().GetResult().Buffer.End); Pipe.Writer.CancelPendingFlush(); Assert.True(awaitable.IsCompleted); FlushResult result = awaitable.GetResult(); Assert.True(result.IsCanceled); }
public async Task DataWrittenOnFlushAsync() { byte[] bytes = Encoding.ASCII.GetBytes("Hello World"); var stream = new MemoryStream(); PipeWriter writer = PipeWriter.Create(stream); bytes.AsSpan().CopyTo(writer.GetSpan(bytes.Length)); writer.Advance(bytes.Length); await writer.FlushAsync(); Assert.Equal(bytes.Length, stream.Length); Assert.Equal("Hello World", Encoding.ASCII.GetString(stream.ToArray())); writer.Complete(); Assert.Equal(0, writer.UnflushedBytes); }
private static ValueTask <bool> Flush(PipeWriter writer) { bool GetResult(FlushResult flush) // tell the calling code whether any more messages // should be written => !(flush.IsCanceled || flush.IsCompleted); async ValueTask <bool> Awaited(ValueTask <FlushResult> incomplete) => GetResult(await incomplete); // apply back-pressure etc var flushTask = writer.FlushAsync(); return(flushTask.IsCompletedSuccessfully ? new ValueTask <bool>(GetResult(flushTask.Result)) : Awaited(flushTask)); }
public async ValueTask Add(byte[] e) { void Write() { var span = _writer.GetSpan(e.Length); for (var i = 0; i < e.Length; i++) { span[i] = e[i]; } _writer.Advance(e.Length); } Write(); await _writer.FlushAsync(); }
public async Task ReadAsync() { PipeWriter writer = _pipe.Writer; PipeReader reader = _pipe.Reader; for (int i = 0; i < InnerIterationCount; i++) { ValueTask <ReadResult> task = reader.ReadAsync(); await writer.WriteAsync(_data); await writer.FlushAsync(); ReadResult result = await task; reader.AdvanceTo(result.Buffer.End); } }
public async Task DefaultReaderSchedulerIgnoresSyncContextIfConfigureAwaitFalse() { // Get off the xunit sync context var previous = SynchronizationContext.Current; try { var sc = new CustomSynchronizationContext(); SynchronizationContext.SetSynchronizationContext(sc); var pipe = new Pipe(); Func <Task> doRead = async() => { ReadResult result = await pipe.Reader.ReadAsync().ConfigureAwait(false); Assert.True(Thread.CurrentThread.IsThreadPoolThread); pipe.Reader.AdvanceTo(result.Buffer.End, result.Buffer.End); pipe.Reader.Complete(); }; // This needs to run on the current SynchronizationContext Task reading = doRead(); PipeWriter buffer = pipe.Writer; buffer.Write(Encoding.UTF8.GetBytes("Hello World")); // We don't want to run any code on our fake sync context await buffer.FlushAsync().ConfigureAwait(false); // Nothing posted to the sync context Assert.Equal(0, sc.Callbacks.Count); pipe.Writer.Complete(); // We don't want to run any code on our fake sync context await reading.ConfigureAwait(false); } finally { SynchronizationContext.SetSynchronizationContext(previous); } }
public async Task FlushCallbackRunsOnWriterScheduler() { using (var pool = new TestMemoryPool()) { using (var scheduler = new ThreadScheduler()) { var pipe = new Pipe( new PipeOptions( pool, resumeWriterThreshold: 32, pauseWriterThreshold: 64, readerScheduler: PipeScheduler.Inline, writerScheduler: scheduler, useSynchronizationContext: false)); PipeWriter writableBuffer = pipe.Writer.WriteEmpty(64); ValueTask <FlushResult> flushAsync = writableBuffer.FlushAsync(); Assert.False(flushAsync.IsCompleted); Func <Task> doWrite = async() => { int oid = Thread.CurrentThread.ManagedThreadId; await flushAsync; Assert.NotEqual(oid, Thread.CurrentThread.ManagedThreadId); pipe.Writer.Complete(); Assert.Equal(Thread.CurrentThread.ManagedThreadId, scheduler.Thread.ManagedThreadId); }; Task writing = doWrite(); ReadResult result = await pipe.Reader.ReadAsync(); pipe.Reader.AdvanceTo(result.Buffer.End, result.Buffer.End); pipe.Reader.Complete(); await writing; } } }
private async Task FillPipeAsync(JT1078TcpSession session, PipeWriter writer) { while (true) { try { Memory <byte> memory = writer.GetMemory(Configuration.MiniNumBufferSize); //设备多久没发数据就断开连接 Receive Timeout. int bytesRead = await session.Client.ReceiveAsync(memory, SocketFlags.None, session.ReceiveTimeout.Token); if (bytesRead == 0) { break; } writer.Advance(bytesRead); } catch (System.ObjectDisposedException ex) { } catch (OperationCanceledException ex) { Logger.LogError($"[Receive Timeout]:{session.Client.RemoteEndPoint}"); break; } catch (System.Net.Sockets.SocketException ex) { Logger.LogError($"[{ex.SocketErrorCode.ToString()},{ex.Message}]:{session.Client.RemoteEndPoint}"); break; } #pragma warning disable CA1031 // Do not catch general exception types catch (Exception ex) { Logger.LogError(ex, $"[Receive Error]:{session.Client.RemoteEndPoint}"); break; } #pragma warning restore CA1031 // Do not catch general exception types FlushResult result = await writer.FlushAsync(); if (result.IsCompleted) { break; } } writer.Complete(); }
public async Task CompleteAsyncDoesNotThrowObjectDisposedException() { byte[] bytes = Encoding.ASCII.GetBytes("Hello World"); var stream = new MemoryStream(); PipeWriter writer = PipeWriter.Create(stream, new StreamPipeWriterOptions(leaveOpen: true)); await writer.FlushAsync(); bytes.AsSpan().CopyTo(writer.GetSpan(bytes.Length)); writer.Advance(bytes.Length); Assert.Equal(0, stream.Length); await writer.CompleteAsync(); Assert.Equal(bytes.Length, stream.Length); Assert.Equal("Hello World", Encoding.ASCII.GetString(stream.ToArray())); }
private async Task WriteLoop(PipeWriter writer, CancellationToken cancellationToken) { try { while (await _listener.Messages.WaitToReadAsync(cancellationToken)) { while (!cancellationToken.IsCancellationRequested && _listener.Messages.TryRead(out var message)) { EventPipeProtocol.WriteMessage(message, writer); } await writer.FlushAsync(); } } catch (OperationCanceledException) { // No-op, we're just shutting down. } }
public async Task WritesUsingGetMemoryWorks() { var bytes = Encoding.ASCII.GetBytes("abcdefghijklmnopqrstuvwzyz"); var stream = new MemoryStream(); var options = new StreamPipeWriterOptions(new HeapBufferPool(), minimumBufferSize: 1); PipeWriter writer = PipeWriter.Create(stream, options); for (int i = 0; i < bytes.Length; i++) { writer.GetMemory().Span[0] = bytes[i]; writer.Advance(1); } await writer.FlushAsync(); Assert.Equal(bytes, stream.ToArray()); writer.Complete(); }
public async Task WriteAndCancellingPendingReadBeforeReadAtLeastAsync() { byte[] bytes = "Hello World" u8.ToArray(); PipeWriter output = Pipe.Writer; output.Write(bytes); await output.FlushAsync(); PipeReader.CancelPendingRead(); ReadResult result = await PipeReader.ReadAtLeastAsync(1000); ReadOnlySequence <byte> buffer = result.Buffer; Assert.False(result.IsCompleted); Assert.True(result.IsCanceled); PipeReader.AdvanceTo(buffer.End); }
public async Task AcceptPipeWriter(PipeWriter writer, int lengthToWrite, CancellationToken cancellationToken) { const int ChunkSize = 5; int writtenBytes = 0; while (writtenBytes < lengthToWrite) { // Write in small chunks to verify that it needn't be written all at once. int bytesToWrite = Math.Min(lengthToWrite - writtenBytes, ChunkSize); await writer.WriteAsync(MemoryBuffer.AsMemory(writtenBytes, bytesToWrite), cancellationToken); await writer.FlushAsync(cancellationToken); writtenBytes += bytesToWrite; } writer.Complete(); }
public async Task FillPipeAsync(Stream sourceStream, PipeWriter writer, CancellationToken cancellationToken) { try { using (var fileStream = new FileStream(Path.GetTempFileName(), FileMode.Create, FileAccess.ReadWrite, FileShare.Read, 16384, FileOptions.Asynchronous | FileOptions.RandomAccess | FileOptions.DeleteOnClose)) { await sourceStream.CopyToAsync(fileStream, 16384, cancellationToken).ConfigureAwait(false); fileStream.Seek(0, SeekOrigin.Begin); using (var zipArchive = SevenZipArchive.Open(fileStream)) using (var zipReader = zipArchive.ExtractAllEntries()) while (zipReader.MoveToNextEntry()) { if (!zipReader.Entry.IsDirectory && zipReader.Entry.Key.EndsWith(".log", StringComparison.InvariantCultureIgnoreCase) && !zipReader.Entry.Key.Contains("tty.log", StringComparison.InvariantCultureIgnoreCase)) { LogSize = zipReader.Entry.Size; using (var entryStream = zipReader.OpenEntryStream()) { int read; FlushResult flushed; do { var memory = writer.GetMemory(Config.MinimumBufferSize); read = await entryStream.ReadAsync(memory, cancellationToken); writer.Advance(read); flushed = await writer.FlushAsync(cancellationToken).ConfigureAwait(false); } while (read > 0 && !(flushed.IsCompleted || flushed.IsCanceled || cancellationToken.IsCancellationRequested)); } writer.Complete(); return; } } Config.Log.Warn("No 7z entries that match the log criteria"); } } catch (Exception e) { Config.Log.Error(e, "Error filling the log pipe"); } writer.Complete(); }
/// <summary> /// Writes all the content of the Stream in the PipeWriter /// </summary> public static async ValueTask CopyToAsync(this Stream stream, PipeWriter writer, int bufferSize, CancellationToken cancellationToken = default(CancellationToken)) { if (stream == null) { throw new ArgumentNullException(nameof(stream)); } if (writer == null) { throw new ArgumentNullException(nameof(writer)); } if (bufferSize <= 0) { throw new ArgumentException("buffer size cannot be negative", nameof(bufferSize)); } try { while (true) { var buffer = writer.GetMemory(bufferSize); int bytesRead = await stream.ReadAsync(buffer, cancellationToken).ConfigureAwait(false); if (bytesRead == 0) { break; } writer.Advance(bytesRead); var flush = await writer.FlushAsync(cancellationToken); if (flush.IsCanceled || flush.IsCompleted) { break; } } writer.Complete(); } catch (Exception err) { writer.Complete(err); } }
public async Task ReceiveAsync( PipeWriter writer, CancellationToken cancellationToken) { WebSocket?webSocket = _webSocket; if (_disposed || webSocket == null) { return; } try { ValueWebSocketReceiveResult socketResult; do { if (webSocket.State != WebSocketState.Open) { break; } Memory <byte> memory = writer.GetMemory(_maxMessageSize); socketResult = await webSocket.ReceiveAsync(memory, cancellationToken); if (socketResult.Count == 0) { break; } writer.Advance(socketResult.Count); FlushResult result = await writer.FlushAsync(cancellationToken); if (result.IsCompleted) { break; } } while (!socketResult.EndOfMessage); } catch { // swallow exception, there's nothing we can reasonably do } }
public async Task ThreadPoolScheduler_SchedulesOnThreadPool() { var pipe = new Pipe(new PipeOptions(readerScheduler: PipeScheduler.ThreadPool, writerScheduler: PipeScheduler.Inline, useSynchronizationContext: false)); async Task DoRead() { // Make sure we aren't on a thread pool thread Assert.False(Thread.CurrentThread.IsThreadPoolThread, "We started on the thread pool"); ValueTask <ReadResult> task = pipe.Reader.ReadAsync(); Assert.False(task.IsCompleted, "Task completed synchronously"); ReadResult result = await task; Assert.True(Thread.CurrentThread.IsThreadPoolThread); pipe.Reader.AdvanceTo(result.Buffer.End, result.Buffer.End); pipe.Reader.Complete(); } bool callbackRan = false; // Wait start the thread and wait for it to finish Task reading = ExecuteOnNonThreadPoolThread(DoRead); PipeWriter buffer = pipe.Writer; #pragma warning disable CS0618 // Type or member is obsolete pipe.Writer.OnReaderCompleted((state, exception) => { callbackRan = true; Assert.True(Thread.CurrentThread.IsThreadPoolThread); }, null); #pragma warning restore CS0618 // Type or member is obsolete buffer.Write(Encoding.UTF8.GetBytes("Hello World")); await buffer.FlushAsync(); await reading; Assert.True(callbackRan); }
private async Task Receive(WebSocket webSocket, PipeWriter writer) { const int minimumBufferSize = 1024; while (true) { try { Memory <byte> memory = writer.GetMemory(minimumBufferSize); WebSocketReceiveResult result = await webSocket.ReceiveAsync(memory); if (result.Count == 0) { break; } // Tell the PipeWriter how much was read writer.Advance(result.Count); switch (result.MessageType) { case WebSocketMessageType.Close: return; case WebSocketMessageType.Text: case WebSocketMessageType.Binary: string value = Encoding.UTF8.GetString(memory.ToArray(), 0, result.Count); Console.WriteLine(value); break; } } catch { break; } // Make the data available to the PipeReader FlushResult flushResult = await writer.FlushAsync(); if (flushResult.IsCompleted) { break; } } // Signal to the reader that we're done writing writer.Complete(); }
public static async Task WriteMessageAsync <TResponse>(this PipeWriter pipeWriter, TResponse response, HttpContextServerCallContext serverCallContext, Action <TResponse, SerializationContext> serializer, bool canFlush) where TResponse : class { var logger = serverCallContext.Logger; try { // Must call StartAsync before the first pipeWriter.GetSpan() in WriteHeader var httpResponse = serverCallContext.HttpContext.Response; if (!httpResponse.HasStarted) { await httpResponse.StartAsync(); } GrpcServerLog.SendingMessage(logger); var serializationContext = serverCallContext.SerializationContext; serializationContext.Reset(); serializationContext.ResponseBufferWriter = pipeWriter; serializer(response, serializationContext); // Flush messages unless WriteOptions.Flags has BufferHint set var flush = canFlush && ((serverCallContext.WriteOptions?.Flags ?? default) & WriteFlags.BufferHint) != WriteFlags.BufferHint; if (flush) { serverCallContext.HasBufferedMessage = false; await pipeWriter.FlushAsync(); } else { // Set flag so buffered message will be written at the end serverCallContext.HasBufferedMessage = true; } GrpcServerLog.MessageSent(serverCallContext.Logger); GrpcEventSource.Log.MessageSent(); } catch (Exception ex) { GrpcServerLog.ErrorSendingMessage(logger, ex); throw; } }
/// <summary> /// Read all to writer /// 读取所有字节到写入器 /// </summary> /// <param name="reader">Reader</param> /// <param name="writer">Pipe writer</param> /// <param name="encoding">Encoding</param> /// <returns>Task</returns> public static async Task ReadAllBytesAsyn(this TextReader reader, PipeWriter writer, Encoding?encoding = null) { // Default encoding encoding ??= Encoding.UTF8; // Memory for read Memory <char> memory = new char[BytesToRead]; int read; while ((read = await reader.ReadBlockAsync(memory)) > 0) { // Write the chars to writer encoding.GetBytes(memory.Span.Slice(0, read), writer); // Make bytes written available await writer.FlushAsync(); } }
private async Task FillPipe(CancellationToken cancellationToken) { await Task.Yield(); try { #if NETSTANDARD2_0 var buffer = new byte[84999]; #endif while (true) { var memory = _writer.GetMemory(84999); #if NETSTANDARD2_0 var bytesRead = await _stream.ReadAsync(buffer, 0, buffer.Length, cancellationToken).ConfigureAwait(false); new Memory <byte>(buffer, 0, bytesRead).CopyTo(memory); #else var bytesRead = await _stream.ReadAsync(memory, cancellationToken).ConfigureAwait(false); #endif if (bytesRead == 0) { break; } _writer.Advance(bytesRead); var result = await _writer.FlushAsync(cancellationToken).ConfigureAwait(false); if (result.IsCompleted) { break; } } } catch { // ignored } finally { await _writer.CompleteAsync().ConfigureAwait(false); } }
public async Task UseSynchronizationContextFalseIgnoresSyncContextForReaderScheduler() { SynchronizationContext previous = SynchronizationContext.Current; var sc = new CustomSynchronizationContext(); try { SynchronizationContext.SetSynchronizationContext(sc); var pipe = new Pipe(new PipeOptions(useSynchronizationContext: false)); Func <Task> doRead = async() => { ReadResult result = await pipe.Reader.ReadAsync(); pipe.Reader.AdvanceTo(result.Buffer.End, result.Buffer.End); pipe.Reader.Complete(); }; // This needs to run on the current SynchronizationContext Task reading = doRead(); PipeWriter buffer = pipe.Writer; buffer.Write("Hello World" u8.ToArray()); // Don't run code on our sync context (we just want to make sure the callbacks) // are scheduled on the sync context await buffer.FlushAsync().ConfigureAwait(false); // Nothing posted to the sync context Assert.Equal(0, sc.Callbacks.Count); pipe.Writer.Complete(); // Don't run code on our sync context await reading.ConfigureAwait(false); } finally { SynchronizationContext.SetSynchronizationContext(previous); } }
public async Task HelloWorldAcrossTwoBlocks() { // block 1 -> block2 // [padding..hello] -> [ world ] PipeWriter writeBuffer = _pipe.Writer; var blockSize = _pipe.Writer.GetMemory().Length; byte[] paddingBytes = Enumerable.Repeat((byte)'a', blockSize - 5).ToArray(); byte[] bytes = Encoding.ASCII.GetBytes("Hello World"); writeBuffer.Write(paddingBytes); writeBuffer.Write(bytes); await writeBuffer.FlushAsync(); ReadResult result = await _pipe.Reader.ReadAsync(); ReadOnlySequence <byte> buffer = result.Buffer; Assert.False(buffer.IsSingleSegment); ReadOnlySequence <byte> helloBuffer = buffer.Slice(blockSize - 5); Assert.False(helloBuffer.IsSingleSegment); var memory = new List <ReadOnlyMemory <byte> >(); foreach (ReadOnlyMemory <byte> m in helloBuffer) { memory.Add(m); } List <ReadOnlyMemory <byte> > spans = memory; _pipe.Reader.AdvanceTo(buffer.Start, buffer.Start); Assert.Equal(2, memory.Count); var helloBytes = new byte[spans[0].Length]; spans[0].Span.CopyTo(helloBytes); var worldBytes = new byte[spans[1].Length]; spans[1].Span.CopyTo(worldBytes); Assert.Equal("Hello", Encoding.ASCII.GetString(helloBytes)); Assert.Equal(" World", Encoding.ASCII.GetString(worldBytes)); }
public async Task DefaultReaderSchedulerRunsOnSynchronizationContext() { SynchronizationContext previous = SynchronizationContext.Current; var sc = new CustomSynchronizationContext(); try { SynchronizationContext.SetSynchronizationContext(sc); var pipe = new Pipe(); Func <Task> doRead = async() => { ReadResult result = await pipe.Reader.ReadAsync(); pipe.Reader.AdvanceTo(result.Buffer.End, result.Buffer.End); pipe.Reader.Complete(); }; // This needs to run on the current SynchronizationContext Task reading = doRead(); PipeWriter buffer = pipe.Writer; buffer.Write(Encoding.UTF8.GetBytes("Hello World")); // Don't run code on our sync context (we just want to make sure the callbacks) // are scheduled on the sync context await buffer.FlushAsync().ConfigureAwait(false); Assert.Equal(1, sc.Callbacks.Count); sc.Callbacks[0].Item1(sc.Callbacks[0].Item2); pipe.Writer.Complete(); // Don't run code on our sync context await reading.ConfigureAwait(false); } finally { SynchronizationContext.SetSynchronizationContext(previous); } }
public int EncodeBinaryMessage(PipeWriter writer, WebSocketMessage pack) { var head = writer.GetSpan(10); head[0] = (byte)((byte)pack.OpCode | 0x80); var headLen = WriteLength(ref head, pack.Data.Length); writer.Advance(headLen); foreach (var dataPiece in pack.Data) { writer.Write(dataPiece.Span); writer.Advance(dataPiece.Length); } writer.FlushAsync().GetAwaiter().GetResult(); return((int)(pack.Data.Length + headLen)); }
private async Task FillPipeAsync(PipeWriter writer, CancellationToken cancellationToken = default) { var ns = _tcpClient.GetStream(); ns.ReadTimeout = 20 * 1000; while (!cancellationToken.IsCancellationRequested) { //var memory = writer.GetMemory(_buffer.Length); try { var bytesRead = await ns.ReadAsync(_buffer, 0, _buffer.Length, cancellationToken); if (bytesRead < 1) { break; } await writer.WriteAsync(new ReadOnlyMemory <byte>(_buffer, 0, bytesRead), cancellationToken); //writer.Advance(bytesRead); } catch (ObjectDisposedException) { // Normal dispose break; } catch (Exception ex) { OnError(ex, true); break; } var result = await writer.FlushAsync(cancellationToken); if (result.IsCompleted) { break; } } writer.Complete(); }
private async Task PipeListener(Socket socket, PipeWriter writer) { const int bufferSize = 512; while (_client.Connected) { var memory = writer.GetMemory(bufferSize); try { if (!socket.Connected) { await _client.Disconnect(); return; } int bytesRead; try { bytesRead = await socket.ReceiveAsync(memory, SocketFlags.None); } catch (SocketException) { await _client.Disconnect(); break; } if (bytesRead == 0) { break; } writer.Advance(bytesRead); } catch (Exception e) { Console.WriteLine(e); // } await writer.FlushAsync(); } }