protected override async Task QuicStreamServer(QuicConnection connection) { await using QuicStream stream = connection.OpenUnidirectionalStream(); await SendData(stream); stream.Shutdown(); await stream.ShutdownWriteCompleted(); }
public static async Task <int> RunClient(IPEndPoint serverEp, CancellationToken token) { using var client = new QuicConnection(new QuicClientConnectionOptions { RemoteEndPoint = serverEp, ClientAuthenticationOptions = new SslClientAuthenticationOptions { ApplicationProtocols = new List <SslApplicationProtocol> { new SslApplicationProtocol("echo") // same as used for server } } }); await client.ConnectAsync(token); try { await using QuicStream stream = client.OpenBidirectionalStream(); // spawn a reader task to not let server be flow-control blocked _ = Task.Run(async() => { byte[] arr = new byte[4 * 1024]; int read; while ((read = await stream.ReadAsync(arr, token)) > 0) { string s = Encoding.ASCII.GetString(arr, 0, read); Console.WriteLine($"Received: {s}"); } }); string line; while ((line = Console.ReadLine()) != null) { // convert into ASCII byte array before sending byte[] bytes = Encoding.ASCII.GetBytes(line); await stream.WriteAsync(bytes, token); // flush the stream to send the data immediately await stream.FlushAsync(token); } // once all stdin is written, close the stream stream.Shutdown(); // wait until the server receives all data await stream.ShutdownWriteCompleted(token); } finally { await client.CloseAsync(0, token); } return(0); }
public async Task QuicStream_ReadWrite_Random_Success(int readSize, int writeSize) { byte[] testBuffer = new byte[8192]; new Random().NextBytes(testBuffer); await Task.WhenAll(DoWrite(), DoRead()); async Task DoWrite() { using QuicConnection clientConnection = CreateQuicConnection(DefaultListener.ListenEndPoint); await clientConnection.ConnectAsync(); await using QuicStream clientStream = clientConnection.OpenUnidirectionalStream(); ReadOnlyMemory <byte> sendBuffer = testBuffer; while (sendBuffer.Length != 0) { ReadOnlyMemory <byte> chunk = sendBuffer.Slice(0, Math.Min(sendBuffer.Length, writeSize)); await clientStream.WriteAsync(chunk); sendBuffer = sendBuffer.Slice(chunk.Length); } clientStream.Shutdown(); await clientStream.ShutdownWriteCompleted(); } async Task DoRead() { using QuicConnection serverConnection = await DefaultListener.AcceptConnectionAsync(); await using QuicStream serverStream = await serverConnection.AcceptStreamAsync(); byte[] receiveBuffer = new byte[testBuffer.Length]; int totalBytesRead = 0; while (totalBytesRead != receiveBuffer.Length) { int bytesRead = await serverStream.ReadAsync(receiveBuffer.AsMemory(totalBytesRead, Math.Min(receiveBuffer.Length - totalBytesRead, readSize))); if (bytesRead == 0) { break; } totalBytesRead += bytesRead; } Assert.True(receiveBuffer.AsSpan().SequenceEqual(testBuffer)); } }
public async Task ReadWrite_Random_Success(int readSize, int writeSize) { byte[] testBuffer = new byte[8192]; new Random().NextBytes(testBuffer); await RunClientServer( async clientConnection => { await using QuicStream clientStream = clientConnection.OpenUnidirectionalStream(); ReadOnlyMemory <byte> sendBuffer = testBuffer; while (sendBuffer.Length != 0) { ReadOnlyMemory <byte> chunk = sendBuffer.Slice(0, Math.Min(sendBuffer.Length, writeSize)); await clientStream.WriteAsync(chunk); sendBuffer = sendBuffer.Slice(chunk.Length); } clientStream.Shutdown(); await clientStream.ShutdownWriteCompleted(); }, async serverConnection => { await using QuicStream serverStream = await serverConnection.AcceptStreamAsync(); byte[] receiveBuffer = new byte[testBuffer.Length]; int totalBytesRead = 0; while (totalBytesRead != receiveBuffer.Length) { int bytesRead = await serverStream.ReadAsync(receiveBuffer.AsMemory(totalBytesRead, Math.Min(receiveBuffer.Length - totalBytesRead, readSize))); if (bytesRead == 0) { break; } totalBytesRead += bytesRead; } Assert.True(receiveBuffer.AsSpan().SequenceEqual(testBuffer)); }); }
private async ValueTask ShutdownWrite(Exception?shutdownReason) { try { lock (_shutdownLock) { _shutdownReason = shutdownReason ?? new ConnectionAbortedException("The Quic transport's send loop completed gracefully."); _log.StreamShutdownWrite(ConnectionId, _shutdownReason); _stream.Shutdown(); } await _stream.ShutdownWriteCompleted(); } catch (Exception ex) { _log.LogWarning(ex, "Stream failed to gracefully shutdown."); // Ignore any errors from Shutdown() since we're tearing down the stream anyway. } }
public async Task WriteTests(int[][] writes, WriteType writeType) { await RunClientServer( async clientConnection => { await using QuicStream stream = clientConnection.OpenUnidirectionalStream(); foreach (int[] bufferLengths in writes) { switch (writeType) { case WriteType.SingleBuffer: foreach (int bufferLength in bufferLengths) { await stream.WriteAsync(new byte[bufferLength]); } break; case WriteType.GatheredBuffers: var buffers = bufferLengths .Select(bufferLength => new ReadOnlyMemory <byte>(new byte[bufferLength])) .ToArray(); await stream.WriteAsync(buffers); break; case WriteType.GatheredSequence: var firstSegment = new BufferSegment(new byte[bufferLengths[0]]); BufferSegment lastSegment = firstSegment; foreach (int bufferLength in bufferLengths.Skip(1)) { lastSegment = lastSegment.Append(new byte[bufferLength]); } var buffer = new ReadOnlySequence <byte>(firstSegment, 0, lastSegment, lastSegment.Memory.Length); await stream.WriteAsync(buffer); break; default: Debug.Fail("Unknown write type."); break; } } stream.Shutdown(); await stream.ShutdownCompleted(); }, async serverConnection => { await using QuicStream stream = await serverConnection.AcceptStreamAsync(); var buffer = new byte[4096]; int receivedBytes = 0, totalBytes = 0; while ((receivedBytes = await stream.ReadAsync(buffer)) != 0) { totalBytes += receivedBytes; } int expectedTotalBytes = writes.SelectMany(x => x).Sum(); Assert.Equal(expectedTotalBytes, totalBytes); stream.Shutdown(); await stream.ShutdownCompleted(); }); }