NetSharp

NetSharp.git
git clone git://git.lenczewski.org/NetSharp.git
Log | Files | Refs | README | LICENSE

commit e85ecc83ab9406fd1089cc587959eb21d83d64da
parent 54f507b485558a201bc314edac955c237ca93332
Author: Mikolaj Lenczewski <mikolaj.lenczewski308@gmail.com>
Date:   Sun, 26 Apr 2020 12:35:37 +0100

We have a memory leak on cancellation...but we cancel.

Diffstat:
MNetSharp/NetSharp/NetSharp.xml | 9+++------
MNetSharp/NetSharp/Sockets/Datagram/DatagramSocketClient.cs | 107++++++++++++++++++++++++++++++++++++++++++++-----------------------------------
MNetSharp/NetSharp/Sockets/SocketClient.cs | 35+++++++++++++++++++++++++++--------
MNetSharp/NetSharp/Sockets/Stream/StreamSocketClient.cs | 255++++++++++++++++++++++++++++++++++++++++++++-----------------------------------
MNetSharp/NetSharpExamples/Benchmarks/UdpSocketClientAsyncBenchmark.cs | 11+----------
MNetSharp/NetSharpExamples/Examples/UdpSocketClientCancellationExample.cs | 52++++++++++++++++++++++++++++++----------------------
MNetSharp/NetSharpExamples/NetSharpExamples.xml | 2+-
MNetSharp/NetSharpExamples/Program.cs | 2+-
8 files changed, 264 insertions(+), 209 deletions(-)

diff --git a/NetSharp/NetSharp/NetSharp.xml b/NetSharp/NetSharp/NetSharp.xml @@ -290,7 +290,7 @@ The remote end point which to which to connect the client. </param> </member> - <member name="M:NetSharp.Sockets.SocketClient.ConnectAsync(System.Net.EndPoint@,System.Threading.CancellationToken)"> + <member name="M:NetSharp.Sockets.SocketClient.ConnectAsync(System.Net.EndPoint@)"> <summary> Asynchronously connects the client to the specified end point. If called on a <see cref="F:System.Net.Sockets.SocketType.Dgram" />-based client, this method configures the default remote host, and the client will ignore any packets not coming from this default host (i.e the given <paramref name="remoteEndPoint" />). @@ -298,9 +298,6 @@ <param name="remoteEndPoint"> The remote end point which to which to connect the client. </param> - <param name="cancellationToken"> - The <see cref="T:System.Threading.CancellationToken" /> upon whose cancellation the connection attempt should be aborted. TODO make functional - </param> <returns> A <see cref="T:System.Threading.Tasks.ValueTask" /> representing the connection attempt. </returns> @@ -346,7 +343,7 @@ The completion source which wraps the event-based APM, and provides an awaitable <see cref="T:System.Threading.Tasks.Task" />. </summary> </member> - <member name="M:NetSharp.Sockets.SocketClient.AsyncTransmissionToken.#ctor(System.Threading.Tasks.TaskCompletionSource{NetSharp.Utils.TransmissionResult}@,System.Threading.CancellationToken@)"> + <member name="M:NetSharp.Sockets.SocketClient.AsyncTransmissionToken.#ctor(System.Threading.Tasks.TaskCompletionSource{NetSharp.Utils.TransmissionResult}@,System.Net.Sockets.SocketAsyncEventArgs@,System.Threading.CancellationToken@)"> <summary> Constructs a new instance of the <see cref="T:NetSharp.Sockets.SocketClient.AsyncTransmissionToken" /> struct. </summary> @@ -567,7 +564,7 @@ <member name="F:NetSharp.Sockets.Stream.StreamSocketClientOptions.PreallocatedTransmissionArgs"> <summary> The number of <see cref="T:System.Net.Sockets.SocketAsyncEventArgs" /> instances that should be preallocated for use in the - <see cref="M:NetSharp.Sockets.Stream.StreamSocketClient.SendAsync(System.Memory{System.Byte},System.Net.Sockets.SocketFlags,System.Threading.CancellationToken)" /> and <see cref="M:NetSharp.Sockets.Stream.StreamSocketClient.ReceiveAsync(System.Memory{System.Byte},System.Net.Sockets.SocketFlags,System.Threading.CancellationToken)" /> methods. + <see cref="M:NetSharp.Sockets.Stream.StreamSocketClient.SendAsync(System.Memory{System.Byte},System.Net.Sockets.SocketFlags)" /> and <see cref="M:NetSharp.Sockets.Stream.StreamSocketClient.ReceiveAsync(System.Memory{System.Byte},System.Net.Sockets.SocketFlags)" /> methods. </summary> </member> <member name="M:NetSharp.Sockets.Stream.StreamSocketClientOptions.#ctor(System.UInt16)"> diff --git a/NetSharp/NetSharp/Sockets/Datagram/DatagramSocketClient.cs b/NetSharp/NetSharp/Sockets/Datagram/DatagramSocketClient.cs @@ -61,29 +61,22 @@ namespace NetSharp.Sockets.Datagram { AsyncOperationToken connectToken = (AsyncOperationToken)args.UserToken; - if (connectToken.CancellationToken.IsCancellationRequested) - { - connectToken.CompletionSource.SetCanceled(); - } - else - { - switch (args.SocketError) - { - case SocketError.Success: - connectToken.CompletionSource.SetResult(true); + if (connectToken.CancellationToken.IsCancellationRequested) return; - break; + switch (args.SocketError) + { + case SocketError.Success: + connectToken.CompletionSource.SetResult(true); - case SocketError.OperationAborted: - Debug.WriteLine("CompleteConnect experienced SocketError.OperationAborted!"); + break; - break; + case SocketError.OperationAborted: + break; - default: - connectToken.CompletionSource.SetException(new SocketException((int)args.SocketError)); + default: + connectToken.CompletionSource.SetException(new SocketException((int)args.SocketError)); - break; - } + break; } TransmissionArgsPool.Return(args); @@ -93,6 +86,12 @@ namespace NetSharp.Sockets.Datagram { AsyncTransmissionToken receiveToken = (AsyncTransmissionToken)args.UserToken; + if (receiveToken.CancellationToken.IsCancellationRequested) + { + Debug.WriteLine("ReceiveFrom completed after being cancelled!"); + return; + } + switch (args.SocketError) { case SocketError.Success: @@ -103,8 +102,7 @@ namespace NetSharp.Sockets.Datagram break; case SocketError.OperationAborted: - Debug.WriteLine("CompleteReceiveFrom experienced SocketError.OperationAborted!"); - + Debug.WriteLine("ReceiveFrom received operation aborted!"); break; default: @@ -120,31 +118,24 @@ namespace NetSharp.Sockets.Datagram { AsyncTransmissionToken sendToken = (AsyncTransmissionToken)args.UserToken; - if (sendToken.CancellationToken.IsCancellationRequested) - { - sendToken.CompletionSource.SetCanceled(); - } - else - { - switch (args.SocketError) - { - case SocketError.Success: - TransmissionResult result = new TransmissionResult(in args); + if (sendToken.CancellationToken.IsCancellationRequested) return; - sendToken.CompletionSource.SetResult(result); + switch (args.SocketError) + { + case SocketError.Success: + TransmissionResult result = new TransmissionResult(in args); - break; + sendToken.CompletionSource.SetResult(result); - case SocketError.OperationAborted: - Debug.WriteLine("CompleteSendTo experienced SocketError.OperationAborted!"); + break; - break; + case SocketError.OperationAborted: + break; - default: - sendToken.CompletionSource.SetException(new SocketException((int)args.SocketError)); + default: + sendToken.CompletionSource.SetException(new SocketException((int)args.SocketError)); - break; - } + break; } TransmissionArgsPool.Return(args); @@ -222,12 +213,23 @@ namespace NetSharp.Sockets.Datagram args.RemoteEndPoint = remoteEndPoint; args.SocketFlags = flags; - args.UserToken = new AsyncTransmissionToken(in tcs, in cancellationToken); + args.UserToken = new AsyncTransmissionToken(in tcs, in args, cancellationToken); + + // TODO find out why the fricc we leak memory + CancellationTokenRegistration cancellationRegistration = + cancellationToken.Register(CancelAsyncTransmissionCallback, args.UserToken); - // TODO implement cancellation for client socket receiveFromAsync - cancellationToken.Register(CancelAsyncTransmissionCallback, new object()); + if (Connection.ReceiveFromAsync(args)) + return new ValueTask<TransmissionResult>( + tcs.Task.ContinueWith((task, state) => + { + ((CancellationTokenRegistration)state).Dispose(); - if (Connection.ReceiveFromAsync(args)) return new ValueTask<TransmissionResult>(tcs.Task); + return task.Result; + }, cancellationRegistration, CancellationToken.None) + ); + + cancellationRegistration.Dispose(); TransmissionResult result = new TransmissionResult(in args); @@ -254,12 +256,23 @@ namespace NetSharp.Sockets.Datagram args.RemoteEndPoint = remoteEndPoint; args.SocketFlags = flags; - args.UserToken = new AsyncTransmissionToken(in tcs, in cancellationToken); + args.UserToken = new AsyncTransmissionToken(in tcs, in args, cancellationToken); + + // TODO find out why the fricc we leak memory + CancellationTokenRegistration cancellationRegistration = + cancellationToken.Register(CancelAsyncTransmissionCallback, args.UserToken); + + if (Connection.SendToAsync(args)) + return new ValueTask<TransmissionResult>( + tcs.Task.ContinueWith((task, state) => + { + ((CancellationTokenRegistration)state).Dispose(); - // TODO implement cancellation for client socket sendToAsync - cancellationToken.Register(CancelAsyncTransmissionCallback, new object()); + return task.Result; + }, cancellationRegistration, CancellationToken.None) + ); - if (Connection.SendToAsync(args)) return new ValueTask<TransmissionResult>(tcs.Task); + cancellationRegistration.Dispose(); TransmissionResult result = new TransmissionResult(in args); diff --git a/NetSharp/NetSharp/Sockets/SocketClient.cs b/NetSharp/NetSharp/Sockets/SocketClient.cs @@ -39,9 +39,13 @@ namespace NetSharp.Sockets { } - protected void CancelAsyncTransmissionCallback(object tokenObj) + protected void CancelAsyncTransmissionCallback(object state) { - Debug.WriteLine("Cancelling asynchronous transmission!"); + AsyncTransmissionToken token = (AsyncTransmissionToken)state; + + token.CompletionSource.SetResult(TransmissionResult.Timeout); + + DestroyTransmissionArgs(token.TransmissionArgs); } /// <summary> @@ -63,9 +67,6 @@ namespace NetSharp.Sockets /// <param name="remoteEndPoint"> /// The remote end point which to which to connect the client. /// </param> - /// <param name="cancellationToken"> - /// The <see cref="CancellationToken" /> upon whose cancellation the connection attempt should be aborted. TODO make functional - /// </param> /// <returns> /// A <see cref="ValueTask" /> representing the connection attempt. /// </returns> @@ -76,9 +77,23 @@ namespace NetSharp.Sockets SocketAsyncEventArgs args = TransmissionArgsPool.Rent(); args.RemoteEndPoint = remoteEndPoint; - args.UserToken = new AsyncOperationToken(in tcs, in cancellationToken); + args.UserToken = new AsyncOperationToken(in tcs, CancellationToken.None); + + // TODO find out why the fricc we leak memory + CancellationTokenRegistration cancellationRegistration = + cancellationToken.Register(CancelAsyncTransmissionCallback, args.UserToken); - if (Connection.ConnectAsync(args)) return new ValueTask(tcs.Task); + if (Connection.ConnectAsync(args)) + return new ValueTask( + tcs.Task.ContinueWith((task, state) => + { + ((CancellationTokenRegistration)state).Dispose(); + + return task.Result; + }, cancellationRegistration, CancellationToken.None) + ); + + cancellationRegistration.Dispose(); TransmissionArgsPool.Return(args); @@ -132,6 +147,8 @@ namespace NetSharp.Sockets /// </summary> public readonly TaskCompletionSource<TransmissionResult> CompletionSource; + public readonly SocketAsyncEventArgs TransmissionArgs; + /// <summary> /// Constructs a new instance of the <see cref="AsyncTransmissionToken" /> struct. /// </summary> @@ -141,10 +158,12 @@ namespace NetSharp.Sockets /// <param name="cancellationToken"> /// The cancellation token to observe during the operation. /// </param> - public AsyncTransmissionToken(in TaskCompletionSource<TransmissionResult> completionSource, in CancellationToken cancellationToken) + public AsyncTransmissionToken(in TaskCompletionSource<TransmissionResult> completionSource, in SocketAsyncEventArgs transmissionArgs, in CancellationToken cancellationToken) { CompletionSource = completionSource; + TransmissionArgs = transmissionArgs; + CancellationToken = cancellationToken; } } diff --git a/NetSharp/NetSharp/Sockets/Stream/StreamSocketClient.cs b/NetSharp/NetSharp/Sockets/Stream/StreamSocketClient.cs @@ -60,24 +60,23 @@ namespace NetSharp.Sockets.Stream { AsyncOperationToken connectToken = (AsyncOperationToken)args.UserToken; - switch (args.SocketError) + if (!connectToken.CancellationToken.IsCancellationRequested) { - case SocketError.Success: - connectToken.CompletionSource.SetResult(true); + switch (args.SocketError) + { + case SocketError.Success: + connectToken.CompletionSource.SetResult(true); - break; - - case SocketError.OperationAborted: - Debug.WriteLine("CompleteConnect experienced SocketError.OperationAborted!"); - - connectToken.CompletionSource.SetResult(false); + break; - break; + case SocketError.OperationAborted: + break; - default: - connectToken.CompletionSource.SetException(new SocketException((int)args.SocketError)); + default: + connectToken.CompletionSource.SetException(new SocketException((int)args.SocketError)); - break; + break; + } } TransmissionArgsPool.Return(args); @@ -87,24 +86,23 @@ namespace NetSharp.Sockets.Stream { AsyncOperationToken disconnectToken = (AsyncOperationToken)args.UserToken; - switch (args.SocketError) + if (!disconnectToken.CancellationToken.IsCancellationRequested) { - case SocketError.Success: - disconnectToken.CompletionSource.SetResult(true); + switch (args.SocketError) + { + case SocketError.Success: + disconnectToken.CompletionSource.SetResult(true); - break; - - case SocketError.OperationAborted: - Debug.WriteLine("CompleteDisconnect experienced SocketError.OperationAborted!"); - - disconnectToken.CompletionSource.SetResult(false); + break; - break; + case SocketError.OperationAborted: + break; - default: - disconnectToken.CompletionSource.SetException(new SocketException((int)args.SocketError)); + default: + disconnectToken.CompletionSource.SetException(new SocketException((int)args.SocketError)); - break; + break; + } } TransmissionArgsPool.Return(args); @@ -114,58 +112,57 @@ namespace NetSharp.Sockets.Stream { AsyncTransmissionToken receiveToken = (AsyncTransmissionToken)args.UserToken; - switch (args.SocketError) + if (!receiveToken.CancellationToken.IsCancellationRequested) { - case SocketError.Success: - Memory<byte> transmissionBuffer = args.MemoryBuffer; - int expectedBytes = transmissionBuffer.Length; + switch (args.SocketError) + { + case SocketError.Success: + Memory<byte> transmissionBuffer = args.MemoryBuffer; + int expectedBytes = transmissionBuffer.Length; - if (args.BytesTransferred == expectedBytes) - { - // buffer was fully received - - TransmissionResult result = new TransmissionResult(in args); - - receiveToken.CompletionSource.SetResult(result); + if (args.BytesTransferred == expectedBytes) + { + // buffer was fully received - TransmissionArgsPool.Return(args); - } - else if (expectedBytes > args.BytesTransferred && args.BytesTransferred > 0) - { - // receive the remaining parts of the buffer + TransmissionResult result = new TransmissionResult(in args); - int receivedBytes = args.BytesTransferred; + receiveToken.CompletionSource.SetResult(result); - args.SetBuffer(receivedBytes, expectedBytes - receivedBytes); + TransmissionArgsPool.Return(args); + } + else if (expectedBytes > args.BytesTransferred && args.BytesTransferred > 0) + { + // receive the remaining parts of the buffer - Connection.ReceiveAsync(args); - } - else - { - // no bytes were received, remote socket is dead + int receivedBytes = args.BytesTransferred; - receiveToken.CompletionSource.SetException(new SocketException((int)SocketError.HostDown)); + args.SetBuffer(receivedBytes, expectedBytes - receivedBytes); - TransmissionArgsPool.Return(args); - } + Connection.ReceiveAsync(args); + } + else + { + // no bytes were received, remote socket is dead - break; + receiveToken.CompletionSource.SetException(new SocketException((int)SocketError.HostDown)); - case SocketError.OperationAborted: - Debug.WriteLine("CompleteReceive experienced SocketError.OperationAborted!"); + TransmissionArgsPool.Return(args); + } - receiveToken.CompletionSource.SetResult(TransmissionResult.Timeout); + break; - TransmissionArgsPool.Return(args); + case SocketError.OperationAborted: + TransmissionArgsPool.Return(args); - break; + break; - default: - receiveToken.CompletionSource.SetException(new SocketException((int)args.SocketError)); + default: + receiveToken.CompletionSource.SetException(new SocketException((int)args.SocketError)); - TransmissionArgsPool.Return(args); + TransmissionArgsPool.Return(args); - break; + break; + } } } @@ -173,58 +170,57 @@ namespace NetSharp.Sockets.Stream { AsyncTransmissionToken sendToken = (AsyncTransmissionToken)args.UserToken; - switch (args.SocketError) + if (!sendToken.CancellationToken.IsCancellationRequested) { - case SocketError.Success: - Memory<byte> transmissionBuffer = args.MemoryBuffer; - int remainingBytes = transmissionBuffer.Length; - - if (args.BytesTransferred == remainingBytes) - { - // buffer was fully sent + switch (args.SocketError) + { + case SocketError.Success: + Memory<byte> transmissionBuffer = args.MemoryBuffer; + int remainingBytes = transmissionBuffer.Length; - TransmissionResult result = new TransmissionResult(in args); + if (args.BytesTransferred == remainingBytes) + { + // buffer was fully sent - sendToken.CompletionSource.SetResult(result); - - TransmissionArgsPool.Return(args); - } - else if (remainingBytes > args.BytesTransferred && args.BytesTransferred > 0) - { - // send the remaining parts of the buffer + TransmissionResult result = new TransmissionResult(in args); - int sentBytes = args.BytesTransferred; + sendToken.CompletionSource.SetResult(result); - args.SetBuffer(sentBytes, remainingBytes - sentBytes); + TransmissionArgsPool.Return(args); + } + else if (remainingBytes > args.BytesTransferred && args.BytesTransferred > 0) + { + // send the remaining parts of the buffer - Connection.SendAsync(args); - } - else - { - // no bytes were sent, remote socket is dead + int sentBytes = args.BytesTransferred; - sendToken.CompletionSource.SetException(new SocketException((int)SocketError.HostDown)); + args.SetBuffer(sentBytes, remainingBytes - sentBytes); - TransmissionArgsPool.Return(args); - } + Connection.SendAsync(args); + } + else + { + // no bytes were sent, remote socket is dead - break; + sendToken.CompletionSource.SetException(new SocketException((int)SocketError.HostDown)); - case SocketError.OperationAborted: - Debug.WriteLine("CompleteSend experienced SocketError.OperationAborted!"); + TransmissionArgsPool.Return(args); + } - sendToken.CompletionSource.SetResult(TransmissionResult.Timeout); + break; - TransmissionArgsPool.Return(args); + case SocketError.OperationAborted: + TransmissionArgsPool.Return(args); - break; + break; - default: - sendToken.CompletionSource.SetException(new SocketException((int)args.SocketError)); + default: + sendToken.CompletionSource.SetException(new SocketException((int)args.SocketError)); - TransmissionArgsPool.Return(args); + TransmissionArgsPool.Return(args); - break; + break; + } } } @@ -299,12 +295,23 @@ namespace NetSharp.Sockets.Stream SocketAsyncEventArgs args = TransmissionArgsPool.Rent(); args.DisconnectReuseSocket = allowSocketReuse; - args.UserToken = new AsyncOperationToken(in tcs, in cancellationToken); + args.UserToken = new AsyncOperationToken(in tcs, CancellationToken.None); + + // TODO find out why the fricc we leak memory + CancellationTokenRegistration cancellationRegistration = + cancellationToken.Register(CancelAsyncTransmissionCallback, args.UserToken); - //TODO implement cancellation for client socket disconnectAsync - //cancellationToken.Register(); + if (Connection.DisconnectAsync(args)) + return new ValueTask( + tcs.Task.ContinueWith((task, state) => + { + ((CancellationTokenRegistration)state).Dispose(); + + return task.Result; + }, cancellationRegistration, CancellationToken.None) + ); - if (Connection.DisconnectAsync(args)) return new ValueTask(tcs.Task); + cancellationRegistration.Dispose(); TransmissionArgsPool.Return(args); @@ -324,8 +331,7 @@ namespace NetSharp.Sockets.Stream return new TransmissionResult(in buffer, in receivedBytes, Connection.RemoteEndPoint); } - public ValueTask<TransmissionResult> ReceiveAsync(Memory<byte> receiveBuffer, SocketFlags flags = SocketFlags.None, - CancellationToken cancellationToken = default) + public ValueTask<TransmissionResult> ReceiveAsync(Memory<byte> receiveBuffer, SocketFlags flags = SocketFlags.None, CancellationToken cancellationToken = default) { TaskCompletionSource<TransmissionResult> tcs = new TaskCompletionSource<TransmissionResult>(); @@ -334,12 +340,23 @@ namespace NetSharp.Sockets.Stream args.SetBuffer(receiveBuffer); args.SocketFlags = flags; - args.UserToken = new AsyncTransmissionToken(in tcs, in cancellationToken); + args.UserToken = new AsyncTransmissionToken(in tcs, in args, CancellationToken.None); - // TODO implement cancellation for client socket receiveAsync - cancellationToken.Register(CancelAsyncTransmissionCallback, new object()); + // TODO find out why the fricc we leak memory + CancellationTokenRegistration cancellationRegistration = + cancellationToken.Register(CancelAsyncTransmissionCallback, args.UserToken); - if (Connection.ReceiveAsync(args)) return new ValueTask<TransmissionResult>(tcs.Task); + if (Connection.ReceiveAsync(args)) + return new ValueTask<TransmissionResult>( + tcs.Task.ContinueWith((task, state) => + { + ((CancellationTokenRegistration)state).Dispose(); + + return task.Result; + }, cancellationRegistration, CancellationToken.None) + ); + + cancellationRegistration.Dispose(); TransmissionResult result = new TransmissionResult(in args); @@ -361,8 +378,7 @@ namespace NetSharp.Sockets.Stream return new TransmissionResult(in buffer, in sentBytes, Connection.RemoteEndPoint); } - public ValueTask<TransmissionResult> SendAsync(Memory<byte> sendBuffer, SocketFlags flags = SocketFlags.None, - CancellationToken cancellationToken = default) + public ValueTask<TransmissionResult> SendAsync(Memory<byte> sendBuffer, SocketFlags flags = SocketFlags.None, CancellationToken cancellationToken = default) { TaskCompletionSource<TransmissionResult> tcs = new TaskCompletionSource<TransmissionResult>(); @@ -371,12 +387,23 @@ namespace NetSharp.Sockets.Stream args.SetBuffer(sendBuffer); args.SocketFlags = flags; - args.UserToken = new AsyncTransmissionToken(in tcs, in cancellationToken); + args.UserToken = new AsyncTransmissionToken(in tcs, in args, CancellationToken.None); + + // TODO find out why the fricc we leak memory + CancellationTokenRegistration cancellationRegistration = + cancellationToken.Register(CancelAsyncTransmissionCallback, args.UserToken); + + if (Connection.SendToAsync(args)) + return new ValueTask<TransmissionResult>( + tcs.Task.ContinueWith((task, state) => + { + ((CancellationTokenRegistration)state).Dispose(); - // TODO implement cancellation for client socket sendAsync - cancellationToken.Register(CancelAsyncTransmissionCallback, new object()); + return task.Result; + }, cancellationRegistration, CancellationToken.None) + ); - if (Connection.SendAsync(args)) return new ValueTask<TransmissionResult>(tcs.Task); + cancellationRegistration.Dispose(); TransmissionResult result = new TransmissionResult(in args); diff --git a/NetSharp/NetSharpExamples/Benchmarks/UdpSocketClientAsyncBenchmark.cs b/NetSharp/NetSharpExamples/Benchmarks/UdpSocketClientAsyncBenchmark.cs @@ -55,7 +55,7 @@ namespace NetSharpExamples.Benchmarks Console.WriteLine($"{PacketCount} packets will be sent per client. This could take a long time (maybe more than a minute)!"); } - using CancellationTokenSource serverCts = new CancellationTokenSource(); + using CancellationTokenSource serverCts = new CancellationTokenSource(); serverCts.Cancel(); Task serverTask = Task.Factory.StartNew(state => ServerTask((CancellationToken)state), serverCts.Token, TaskCreationOptions.LongRunning); BenchmarkHelper benchmarkHelper = new BenchmarkHelper(); @@ -85,15 +85,6 @@ namespace NetSharpExamples.Benchmarks benchmarkHelper.PrintBandwidthStats(0, PacketCount, NetworkPacket.TotalSize); benchmarkHelper.PrintRttStats(0); - - serverCts.Cancel(); - try - { - serverTask.Dispose(); - } - catch (Exception) { } - - Console.WriteLine($"UDP Client Benchmark finished!"); } } } \ No newline at end of file diff --git a/NetSharp/NetSharpExamples/Examples/UdpSocketClientCancellationExample.cs b/NetSharp/NetSharpExamples/Examples/UdpSocketClientCancellationExample.cs @@ -20,7 +20,7 @@ namespace NetSharpExamples.Examples /// <summary> /// A read only server. Never sends out data! /// </summary> - private Task ServerTask(CancellationToken cancellationToken) + private Task ServerTask() { Socket server = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); @@ -30,12 +30,18 @@ namespace NetSharpExamples.Examples EndPoint remoteEndPoint = new IPEndPoint(IPAddress.Any, 0); - while (!cancellationToken.IsCancellationRequested) + for (int i = 0; i < 10; i++) { server.ReceiveFrom(transmissionBuffer, ref remoteEndPoint); } + for (int i = 0; i < 9; i++) + { + server.SendTo(transmissionBuffer, remoteEndPoint); + } + server.Close(); + server.Dispose(); return Task.CompletedTask; } @@ -43,11 +49,10 @@ namespace NetSharpExamples.Examples /// <inheritdoc /> public async Task RunAsync() { - using CancellationTokenSource serverCts = new CancellationTokenSource(); - Task serverTask = Task.Factory.StartNew(state => ServerTask((CancellationToken)state), serverCts.Token, TaskCreationOptions.LongRunning); + Task serverTask = Task.Factory.StartNew(ServerTask, TaskCreationOptions.LongRunning); DatagramSocketClientOptions clientOptions = new DatagramSocketClientOptions((ushort)2); - using DatagramSocketClient client = new DatagramSocketClient(AddressFamily.InterNetwork, ProtocolType.Udp, clientOptions); + DatagramSocketClient client = new DatagramSocketClient(AddressFamily.InterNetwork, ProtocolType.Udp, clientOptions); byte[] sendBuffer = new byte[NetworkPacket.TotalSize]; byte[] receiveBuffer = new byte[NetworkPacket.TotalSize]; @@ -60,7 +65,8 @@ namespace NetSharpExamples.Examples for (int i = 0; i < 10; i++) { - CancellationTokenSource sendCts = new CancellationTokenSource(); + using CancellationTokenSource sendCts = new CancellationTokenSource(); + using CancellationTokenSource receiveCts = new CancellationTokenSource(); sendCts.CancelAfter(timeout); TransmissionResult sendResult = await client.SendToAsync(remoteEndPoint, sendBuffer, SocketFlags.None, sendCts.Token); @@ -68,26 +74,28 @@ namespace NetSharpExamples.Examples if (sendResult.TimedOut()) { Console.WriteLine("Send timed out!"); - - continue; } - - Console.WriteLine($"Sent {sendResult.Count} bytes of data!"); - - CancellationTokenSource receiveCts = new CancellationTokenSource(); - - receiveCts.CancelAfter(timeout); - TransmissionResult receiveResult = await client.ReceiveFromAsync(remoteEndPoint, receiveBuffer, SocketFlags.None, receiveCts.Token); - - if (receiveResult.TimedOut()) + else { - Console.WriteLine("Receive timed out!"); - - continue; + Console.WriteLine($"Sent {sendResult.Count} bytes of data!"); + + receiveCts.CancelAfter(timeout); + TransmissionResult receiveResult = await client.ReceiveFromAsync(remoteEndPoint, receiveBuffer, SocketFlags.None, receiveCts.Token); + + if (receiveResult.TimedOut()) + { + Console.WriteLine("Receive timed out!"); + } + else + { + Console.WriteLine($"Received {receiveResult.Count} bytes of data!"); + } } - - Console.WriteLine($"Received {receiveResult.Count} bytes of data!"); } + + client.Dispose(); + + Console.WriteLine($"UDP Socket Client finished!"); } } } \ No newline at end of file diff --git a/NetSharp/NetSharpExamples/NetSharpExamples.xml b/NetSharp/NetSharpExamples/NetSharpExamples.xml @@ -85,7 +85,7 @@ <member name="P:NetSharpExamples.Examples.UdpSocketClientCancellationExample.Name"> <inheritdoc /> </member> - <member name="M:NetSharpExamples.Examples.UdpSocketClientCancellationExample.ServerTask(System.Threading.CancellationToken)"> + <member name="M:NetSharpExamples.Examples.UdpSocketClientCancellationExample.ServerTask"> <summary> A read only server. Never sends out data! </summary> diff --git a/NetSharp/NetSharpExamples/Program.cs b/NetSharp/NetSharpExamples/Program.cs @@ -16,7 +16,7 @@ namespace NetSharpExamples new UdpSocketClientSyncBenchmark(), new UdpSocketClientAsyncBenchmark(), new UdpSocketClientExample(), - //new UdpSocketClientCancellationExample(), // TODO make functional + new UdpSocketClientCancellationExample(), // TODO make functional // TCP socket server and client examples new TcpSocketServerBenchmark(),