protected virtual void Dispose(bool disposing) { _output.CompleteWriter(); _output.CompleteReader(); _input.CompleteWriter(); _input.CompleteReader(); }
public async Task WriteLargeDataBinary(int length) { byte[] data = new byte[length]; new Random(length).NextBytes(data); using (var memoryPool = new MemoryPool()) { var readerWriter = new PipelineReaderWriter(memoryPool); var output = readerWriter.Alloc(); output.Write(data); var foo = output.Memory.IsEmpty; // trying to see if .Memory breaks await output.FlushAsync(); readerWriter.CompleteWriter(); int offset = 0; while (true) { var result = await readerWriter.ReadAsync(); var input = result.Buffer; if (input.Length == 0) { break; } Assert.True(input.Equals(new Span <byte>(data, offset, input.Length))); offset += input.Length; readerWriter.Advance(input.End); } Assert.Equal(data.Length, offset); } }
public async Task WriteLargeDataTextUtf8(int length) { string data = new string('#', length); FillRandomStringData(data, length); using (var memoryPool = new MemoryPool()) { var readerWriter = new PipelineReaderWriter(memoryPool); var output = readerWriter.Alloc(); output.Append(data, TextEncoding.Utf8); var foo = output.Memory.IsEmpty; // trying to see if .Memory breaks await output.FlushAsync(); readerWriter.CompleteWriter(); int offset = 0; while (true) { var result = await readerWriter.ReadAsync(); var input = result.Buffer; if (input.Length == 0) { break; } string s = ReadableBufferExtensions.GetUtf8String(input); Assert.Equal(data.Substring(offset, input.Length), s); offset += input.Length; readerWriter.Advance(input.End); } Assert.Equal(data.Length, offset); } }
public async Task WriteLargeDataBinary(int length) { byte[] data = new byte[length]; new Random(length).NextBytes(data); using (var memoryPool = new MemoryPool()) { var readerWriter = new PipelineReaderWriter(memoryPool); var output = readerWriter.Alloc(); output.Write(data); var foo = output.Memory.IsEmpty; // trying to see if .Memory breaks await output.FlushAsync(); readerWriter.CompleteWriter(); int offset = 0; while (true) { var result = await readerWriter.ReadAsync(); var input = result.Buffer; if (input.Length == 0) break; Assert.True(input.Equals(new Span<byte>(data, offset, input.Length))); offset += input.Length; readerWriter.Advance(input.End); } Assert.Equal(data.Length, offset); } }
/// <summary> /// Releases all resources owned by the connection /// </summary> protected virtual void Dispose(bool disposing) { if (disposing) { _output.CompleteWriter(); _output.CompleteReader(); _input.CompleteWriter(); _input.CompleteReader(); GC.SuppressFinalize(this); _socket?.Dispose(); _socket = null; if (_ownsFactory) { _factory?.Dispose(); } _factory = null; } }
public void ReceiveBeginComplete(uint bytesTransferred) { if (bytesTransferred == 0 || _input.Writing.IsCompleted) { _input.CompleteWriter(); } else { _buffer.Advance((int)bytesTransferred); _buffer.Commit(); ProcessReceives(); } }
public void Complete(Exception exception = null) { _readerWriter.CompleteWriter(exception); }
public void FinishWriting() => _readerWriter.CompleteWriter();
private async void ReceiveFromSocketAndPushToWriterAsync() { SocketAsyncEventArgs args = null; try { // if the consumer says they don't want the data, we need to shut down the receive GC.KeepAlive(_input.Writing.ContinueWith(delegate {// GC.KeepAlive here just to shut the compiler up try { Socket.Shutdown(SocketShutdown.Receive); } catch { } })); // wait for someone to be interested in data before we // start allocating buffers and probing the socket await _input.ReadingStarted; args = GetOrCreateSocketAsyncEventArgs(); while (!_input.Writing.IsCompleted) { bool haveWriteBuffer = false; WritableBuffer buffer = default(WritableBuffer); var initialSegment = default(ArraySegment <byte>); try { int bytesFromInitialDataBuffer = 0; if (Socket.Available == 0) { // now, this gets a bit messy unfortunately, because support for the ideal option // (zero-length reads) is platform dependent switch (_bufferStyle) { case BufferStyle.Unknown: try { initialSegment = await ReceiveInitialDataUnknownStrategyAsync(args); } catch { initialSegment = default(ArraySegment <byte>); } if (initialSegment.Array == null) { continue; // redo from start } break; case BufferStyle.UseZeroLengthBuffer: // if we already have a buffer, use that (but: zero count); otherwise use a shared // zero-length; this avoids constantly changing the buffer that the args use, which // avoids some overheads args.SetBuffer(args.Buffer ?? _zeroLengthBuffer, 0, 0); // await async for the io work to be completed await Socket.ReceiveSignalAsync(args); break; case BufferStyle.UseSmallBuffer: // We need to do a speculative receive with a *cheap* buffer while we wait for input; it would be *nice* if // we could do a zero-length receive, but this is not supported equally on all platforms (fine on Windows, but // linux hates it). The key aim here is to make sure that we don't tie up an entire block from the memory pool // waiting for input on a socket; fine for 1 socket, not so fine for 100,000 sockets // do a short receive while we wait (async) for data initialSegment = LeaseSmallBuffer(); args.SetBuffer(initialSegment.Array, initialSegment.Offset, initialSegment.Count); // await async for the io work to be completed await Socket.ReceiveSignalAsync(args); break; } if (args.SocketError != SocketError.Success) { throw new SocketException((int)args.SocketError); } // note we can't check BytesTransferred <= 0, as we always // expect 0; but if we returned, we expect data to be // buffered *on the socket*, else EOF if ((bytesFromInitialDataBuffer = args.BytesTransferred) <= 0) { if (ReferenceEquals(initialSegment.Array, _zeroLengthBuffer)) { // sentinel value that means we should just // consume sync (we expect there to be data) initialSegment = default(ArraySegment <byte>); } else { // socket reported EOF RecycleSmallBuffer(ref initialSegment); } if (Socket.Available == 0) { // yup, definitely an EOF break; } } } // note that we will try to coalesce things here to reduce the number of flushes; we // certainly want to coalesce the initial buffer (from the speculative receive) with the initial // data, but we probably don't want to buffer indefinitely; for now, it will buffer up to 4 pages // before flushing (entirely arbitrarily) - might want to make this configurable later buffer = _input.Alloc(SmallBufferSize * 2); haveWriteBuffer = true; const int FlushInputEveryBytes = 4 * MemoryPool.MaxPooledBlockLength; if (initialSegment.Array != null) { // need to account for anything that we got in the speculative receive if (bytesFromInitialDataBuffer != 0) { buffer.Write(new Span <byte>(initialSegment.Array, initialSegment.Offset, bytesFromInitialDataBuffer)); } // make the small buffer available to other consumers RecycleSmallBuffer(ref initialSegment); } bool isEOF = false; while (Socket.Available != 0 && buffer.BytesWritten < FlushInputEveryBytes) { buffer.Ensure(); // ask for *something*, then use whatever is available (usually much much more) SetBuffer(buffer.Memory, args); // await async for the io work to be completed await Socket.ReceiveSignalAsync(args); // either way, need to validate if (args.SocketError != SocketError.Success) { throw new SocketException((int)args.SocketError); } int len = args.BytesTransferred; if (len <= 0) { // socket reported EOF isEOF = true; break; } // record what data we filled into the buffer buffer.Advance(len); } if (isEOF) { break; } } finally { RecycleSmallBuffer(ref initialSegment); if (haveWriteBuffer) { await buffer.FlushAsync(); } } } _input.CompleteWriter(); } catch (Exception ex) { // don't trust signal after an error; someone else could // still have it and invoke Set if (args != null) { args.UserToken = null; } _input?.CompleteWriter(ex); } finally { RecycleSocketAsyncEventArgs(args); } }
public async Task WriteLargeDataTextUtf8(int length) { string data = new string('#', length); FillRandomStringData(data, length); using (var memoryPool = new MemoryPool()) { var readerWriter = new PipelineReaderWriter(memoryPool); var output = readerWriter.Alloc(); output.Append(data, TextEncoding.Utf8); var foo = output.Memory.IsEmpty; // trying to see if .Memory breaks await output.FlushAsync(); readerWriter.CompleteWriter(); int offset = 0; while (true) { var result = await readerWriter.ReadAsync(); var input = result.Buffer; if (input.Length == 0) break; string s = ReadableBufferExtensions.GetUtf8String(input); Assert.Equal(data.Substring(offset, input.Length), s); offset += input.Length; readerWriter.Advance(input.End); } Assert.Equal(data.Length, offset); } }