commit 99fba2a642114c8a22cfe50f8a7d097cd885f47a parent f12027782987cc6dc066918f1ad26ba4d177f4a0 Author: Mikolaj Lenczewski <mikolaj.lenczewski308@gmail.com> Date: Sun, 26 Apr 2020 20:38:09 +0100 Consolidated datagram and stream socket client Send/Receive network operations into single interface held in SocketClient. Fixed occurences across the project. Diffstat:
12 files changed, 339 insertions(+), 71 deletions(-)
diff --git a/NetSharp/NetSharp/NetSharp.csproj b/NetSharp/NetSharp/NetSharp.csproj @@ -17,12 +17,6 @@ </PropertyGroup> <ItemGroup> - <Compile Remove="Interfaces\**" /> - <EmbeddedResource Remove="Interfaces\**" /> - <None Remove="Interfaces\**" /> - </ItemGroup> - - <ItemGroup> <PackageReference Include="Microsoft.CSharp" Version="4.7.0" /> <PackageReference Include="Microsoft.Extensions.ObjectPool" Version="3.1.2" /> <PackageReference Include="System.Threading.Channels" Version="4.7.0" /> diff --git a/NetSharp/NetSharp/NetSharp.xml b/NetSharp/NetSharp/NetSharp.xml @@ -169,7 +169,7 @@ <member name="F:NetSharp.Sockets.Datagram.DatagramSocketClientOptions.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.Datagram.DatagramSocketClient.SendToAsync(System.Net.EndPoint,System.ReadOnlyMemory{System.Byte},System.Net.Sockets.SocketFlags,System.Threading.CancellationToken)" /> and <see cref="M:NetSharp.Sockets.Datagram.DatagramSocketClient.ReceiveFromAsync(System.Net.EndPoint,System.Memory{System.Byte},System.Net.Sockets.SocketFlags,System.Threading.CancellationToken)" /> methods. + <see cref="!:DatagramSocketClient.SendToAsyncInternal" /> and <see cref="!:DatagramSocketClient.ReceiveFromAsyncInternal" /> methods. </summary> </member> <member name="M:NetSharp.Sockets.Datagram.DatagramSocketClientOptions.#ctor(System.UInt16)"> @@ -195,6 +195,18 @@ <member name="M:NetSharp.Sockets.Datagram.DatagramSocketClient.ResetTransmissionArgs(System.Net.Sockets.SocketAsyncEventArgs)"> <inheritdoc /> </member> + <member name="M:NetSharp.Sockets.Datagram.DatagramSocketClient.Receive(System.Net.EndPoint@,System.Byte[],System.Net.Sockets.SocketFlags)"> + <inheritdoc /> + </member> + <member name="M:NetSharp.Sockets.Datagram.DatagramSocketClient.ReceiveAsync(System.Net.EndPoint@,System.Memory{System.Byte},System.Net.Sockets.SocketFlags,System.Threading.CancellationToken)"> + <inheritdoc /> + </member> + <member name="M:NetSharp.Sockets.Datagram.DatagramSocketClient.Send(System.Net.EndPoint@,System.Byte[],System.Net.Sockets.SocketFlags)"> + <inheritdoc /> + </member> + <member name="M:NetSharp.Sockets.Datagram.DatagramSocketClient.SendAsync(System.Net.EndPoint@,System.ReadOnlyMemory{System.Byte},System.Net.Sockets.SocketFlags,System.Threading.CancellationToken)"> + <inheritdoc /> + </member> <member name="T:NetSharp.Sockets.Datagram.DatagramSocketServerOptions"> <summary> Provides additional configuration options for a <see cref="T:NetSharp.Sockets.Datagram.DatagramSocketServer" /> instance. @@ -281,6 +293,30 @@ The number of transmission args to preallocate. </param> </member> + <member name="M:NetSharp.Sockets.SocketClient.CancelAsyncOperationCallback(System.Object)"> + <summary> + Callback for the cancellation of an asynchronous network operation. + </summary> + <param name="state"> + The <see cref="T:System.Net.Sockets.SocketAsyncEventArgs" /> state object for the operation. + </param> + </member> + <member name="M:NetSharp.Sockets.SocketClient.CancelAsyncReceiveCallback(System.Object)"> + <summary> + Callback for the cancellation of an asynchronous network receive operation. + </summary> + <param name="state"> + The <see cref="T:System.Net.Sockets.SocketAsyncEventArgs" /> state object for the operation. + </param> + </member> + <member name="M:NetSharp.Sockets.SocketClient.CancelAsyncSendCallback(System.Object)"> + <summary> + Callback for the cancellation of an asynchronous network send operation. + </summary> + <param name="state"> + The <see cref="T:System.Net.Sockets.SocketAsyncEventArgs" /> state object for the operation. + </param> + </member> <member name="M:NetSharp.Sockets.SocketClient.Connect(System.Net.EndPoint@)"> <summary> 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 @@ -298,10 +334,92 @@ <param name="remoteEndPoint"> The remote end point which to which to connect the client. </param> + <param name="cancellationToken"> + The cancellation token to observe during the asynchronous operation. + </param> <returns> A <see cref="T:System.Threading.Tasks.ValueTask" /> representing the connection attempt. </returns> </member> + <member name="M:NetSharp.Sockets.SocketClient.Receive(System.Net.EndPoint@,System.Byte[],System.Net.Sockets.SocketFlags)"> + <summary> + Listens for data from the specified endpoint, placing the data in the given buffer. On connection-oriented protocols, the given endpoint + is ignored in favour of the default remote host set up by a call to <see cref="M:NetSharp.Sockets.SocketClient.Connect(System.Net.EndPoint@)" /> or <see cref="M:NetSharp.Sockets.SocketClient.ConnectAsync(System.Net.EndPoint@,System.Threading.CancellationToken)" />. + </summary> + <param name="remoteEndPoint"> + The remote endpoint from which data should be received. Ignored on connection-oriented protocols. + </param> + <param name="receiveBuffer"> + The buffer into which data is to be received. + </param> + <param name="flags"> + The socket flags associated with the send operation. + </param> + <returns> + The result of the receive operation. + </returns> + </member> + <member name="M:NetSharp.Sockets.SocketClient.ReceiveAsync(System.Net.EndPoint@,System.Memory{System.Byte},System.Net.Sockets.SocketFlags,System.Threading.CancellationToken)"> + <summary> + Asynchronously listens for data from the specified endpoint, placing the data in the given buffer. On connection-oriented protocols, the + given endpoint is ignored in favour of the default remote host set up by a call to <see cref="M:NetSharp.Sockets.SocketClient.Connect(System.Net.EndPoint@)" /> or <see cref="M:NetSharp.Sockets.SocketClient.ConnectAsync(System.Net.EndPoint@,System.Threading.CancellationToken)" />. + </summary> + <param name="remoteEndPoint"> + The remote endpoint from which data should be received. Ignored on connection-oriented protocols. + </param> + <param name="receiveBuffer"> + The buffer into which data is to be received. + </param> + <param name="flags"> + The socket flags associated with the send operation. + </param> + <param name="cancellationToken"> + The cancellation token to observe during the asynchronous operation. + </param> + <returns> + The result of the asynchronous receive operation. + </returns> + </member> + <member name="M:NetSharp.Sockets.SocketClient.Send(System.Net.EndPoint@,System.Byte[],System.Net.Sockets.SocketFlags)"> + <summary> + Sends the data in the given buffer to the specified endpoint. On connection-oriented protocols, the given endpoint is ignored in favour of + the default remote host set up by a call to <see cref="M:NetSharp.Sockets.SocketClient.Connect(System.Net.EndPoint@)" /> or <see cref="M:NetSharp.Sockets.SocketClient.ConnectAsync(System.Net.EndPoint@,System.Threading.CancellationToken)" />. + </summary> + <param name="remoteEndPoint"> + The remote endpoint to which data should be sent. Ignored on connection-oriented protocols. + </param> + <param name="sendBuffer"> + The buffer containing the outgoing data to be sent. + </param> + <param name="flags"> + The socket flags associated with the send operation. + </param> + <returns> + The result of the send operation. + </returns> + </member> + <member name="M:NetSharp.Sockets.SocketClient.SendAsync(System.Net.EndPoint@,System.ReadOnlyMemory{System.Byte},System.Net.Sockets.SocketFlags,System.Threading.CancellationToken)"> + <summary> + Asynchronously sends the data in the given buffer to the specified endpoint. On connection-oriented protocols, the given endpoint is + ignored in favour of the default remote host set up by a call to <see cref="M:NetSharp.Sockets.SocketClient.Connect(System.Net.EndPoint@)" /> or <see cref="M:NetSharp.Sockets.SocketClient.ConnectAsync(System.Net.EndPoint@,System.Threading.CancellationToken)" />. + </summary> + <param name="remoteEndPoint"> + The remote endpoint to which data should be sent. Ignored on connection-oriented protocols. + </param> + <param name="sendBuffer"> + The buffer containing the outgoing data to be sent. The contents of the buffer are copied to an internally maintained buffer when the call + is made. + </param> + <param name="flags"> + The socket flags associated with the send operation. + </param> + <param name="cancellationToken"> + The cancellation token to observe during the asynchronous operation. + </param> + <returns> + The result of the asynchronous send operation. + </returns> + </member> <member name="T:NetSharp.Sockets.SocketClient.AsyncOperationToken"> <summary> A state token for asynchronous socket operations. @@ -369,6 +487,11 @@ The completion source which wraps the event-based APM, and provides an awaitable <see cref="T:System.Threading.Tasks.Task" />. </summary> </member> + <member name="F:NetSharp.Sockets.SocketClient.AsyncSendToken.RentedBuffer"> + <summary> + The rented buffer which holds the user's data. + </summary> + </member> <member name="M:NetSharp.Sockets.SocketClient.AsyncSendToken.#ctor(System.Threading.Tasks.TaskCompletionSource{NetSharp.Utils.TransmissionResult}@,System.Byte[]@,System.Threading.CancellationToken@)"> <summary> Constructs a new instance of the <see cref="T:NetSharp.Sockets.SocketClient.AsyncSendToken" /> struct. @@ -376,6 +499,9 @@ <param name="completionSource"> The completion source to trigger when the IO operation completes. </param> + <param name="rentedBuffer"> + The buffer holding the user's data. + </param> <param name="cancellationToken"> The cancellation token to observe during the operation. </param> @@ -590,7 +716,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.ReadOnlyMemory{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.Net.EndPoint@,System.ReadOnlyMemory{System.Byte},System.Net.Sockets.SocketFlags,System.Threading.CancellationToken)" /> and <see cref="M:NetSharp.Sockets.Stream.StreamSocketClient.ReceiveAsync(System.Net.EndPoint@,System.Memory{System.Byte},System.Net.Sockets.SocketFlags,System.Threading.CancellationToken)" /> methods. </summary> </member> <member name="M:NetSharp.Sockets.Stream.StreamSocketClientOptions.#ctor(System.UInt16)"> @@ -616,6 +742,18 @@ <member name="M:NetSharp.Sockets.Stream.StreamSocketClient.ResetTransmissionArgs(System.Net.Sockets.SocketAsyncEventArgs)"> <inheritdoc /> </member> + <member name="M:NetSharp.Sockets.Stream.StreamSocketClient.Receive(System.Net.EndPoint@,System.Byte[],System.Net.Sockets.SocketFlags)"> + <inheritdoc /> + </member> + <member name="M:NetSharp.Sockets.Stream.StreamSocketClient.ReceiveAsync(System.Net.EndPoint@,System.Memory{System.Byte},System.Net.Sockets.SocketFlags,System.Threading.CancellationToken)"> + <inheritdoc /> + </member> + <member name="M:NetSharp.Sockets.Stream.StreamSocketClient.Send(System.Net.EndPoint@,System.Byte[],System.Net.Sockets.SocketFlags)"> + <inheritdoc /> + </member> + <member name="M:NetSharp.Sockets.Stream.StreamSocketClient.SendAsync(System.Net.EndPoint@,System.ReadOnlyMemory{System.Byte},System.Net.Sockets.SocketFlags,System.Threading.CancellationToken)"> + <inheritdoc /> + </member> <member name="T:NetSharp.Sockets.Stream.StreamSocketServerOptions"> <summary> Provides additional configuration options for a <see cref="T:NetSharp.Sockets.Stream.StreamSocketServer" /> instance. diff --git a/NetSharp/NetSharp/Sockets/Datagram/DatagramSocketClient.cs b/NetSharp/NetSharp/Sockets/Datagram/DatagramSocketClient.cs @@ -22,7 +22,7 @@ namespace NetSharp.Sockets.Datagram /// <summary> /// The number of <see cref="SocketAsyncEventArgs" /> instances that should be preallocated for use in the - /// <see cref="DatagramSocketClient.SendToAsync" /> and <see cref="DatagramSocketClient.ReceiveFromAsync" /> methods. + /// <see cref="DatagramSocketClient.SendToAsyncInternal" /> and <see cref="DatagramSocketClient.ReceiveFromAsyncInternal" /> methods. /// </summary> public readonly ushort PreallocatedTransmissionArgs; @@ -190,15 +190,18 @@ namespace NetSharp.Sockets.Datagram { } - public TransmissionResult ReceiveFrom(ref EndPoint remoteEndPoint, byte[] receiveBuffer, SocketFlags flags = SocketFlags.None) + /// <inheritdoc /> + public override TransmissionResult Receive(in EndPoint remoteEndPoint, byte[] receiveBuffer, SocketFlags flags = SocketFlags.None) { - int receivedBytes = Connection.ReceiveFrom(receiveBuffer, flags, ref remoteEndPoint); + EndPoint actualEndPoint = remoteEndPoint; + int receivedBytes = Connection.ReceiveFrom(receiveBuffer, flags, ref actualEndPoint); - return new TransmissionResult(in receiveBuffer, in receivedBytes, in remoteEndPoint); + return new TransmissionResult(in receiveBuffer, in receivedBytes, in actualEndPoint); } - public ValueTask<TransmissionResult> ReceiveFromAsync(EndPoint remoteEndPoint, Memory<byte> receiveBuffer, - SocketFlags flags = SocketFlags.None, CancellationToken cancellationToken = default) + /// <inheritdoc /> + public override ValueTask<TransmissionResult> ReceiveAsync(in EndPoint remoteEndPoint, Memory<byte> receiveBuffer, SocketFlags flags = SocketFlags.None, + CancellationToken cancellationToken = default) { TaskCompletionSource<TransmissionResult> tcs = new TaskCompletionSource<TransmissionResult>(); @@ -240,15 +243,17 @@ namespace NetSharp.Sockets.Datagram return new ValueTask<TransmissionResult>(result); } - public TransmissionResult SendTo(EndPoint remoteEndPoint, byte[] sendBuffer, SocketFlags flags = SocketFlags.None) + /// <inheritdoc /> + public override TransmissionResult Send(in EndPoint remoteEndPoint, byte[] sendBuffer, SocketFlags flags = SocketFlags.None) { int sentBytes = Connection.SendTo(sendBuffer, flags, remoteEndPoint); return new TransmissionResult(in sendBuffer, in sentBytes, in remoteEndPoint); } - public ValueTask<TransmissionResult> SendToAsync(EndPoint remoteEndPoint, ReadOnlyMemory<byte> sendBuffer, - SocketFlags flags = SocketFlags.None, CancellationToken cancellationToken = default) + /// <inheritdoc /> + public override ValueTask<TransmissionResult> SendAsync(in EndPoint remoteEndPoint, ReadOnlyMemory<byte> sendBuffer, SocketFlags flags = SocketFlags.None, + CancellationToken cancellationToken = default) { TaskCompletionSource<TransmissionResult> tcs = new TaskCompletionSource<TransmissionResult>(); diff --git a/NetSharp/NetSharp/Sockets/SocketClient.cs b/NetSharp/NetSharp/Sockets/SocketClient.cs @@ -1,5 +1,6 @@ using NetSharp.Utils; +using System; using System.Net; using System.Net.Sockets; using System.Threading; @@ -37,6 +38,12 @@ namespace NetSharp.Sockets { } + /// <summary> + /// Callback for the cancellation of an asynchronous network operation. + /// </summary> + /// <param name="state"> + /// The <see cref="SocketAsyncEventArgs" /> state object for the operation. + /// </param> protected void CancelAsyncOperationCallback(object state) { SocketAsyncEventArgs args = (SocketAsyncEventArgs)state; @@ -48,6 +55,12 @@ namespace NetSharp.Sockets DestroyTransmissionArgs(args); } + /// <summary> + /// Callback for the cancellation of an asynchronous network receive operation. + /// </summary> + /// <param name="state"> + /// The <see cref="SocketAsyncEventArgs" /> state object for the operation. + /// </param> protected void CancelAsyncReceiveCallback(object state) { SocketAsyncEventArgs args = (SocketAsyncEventArgs)state; @@ -59,6 +72,12 @@ namespace NetSharp.Sockets DestroyTransmissionArgs(args); } + /// <summary> + /// Callback for the cancellation of an asynchronous network send operation. + /// </summary> + /// <param name="state"> + /// The <see cref="SocketAsyncEventArgs" /> state object for the operation. + /// </param> protected void CancelAsyncSendCallback(object state) { SocketAsyncEventArgs args = (SocketAsyncEventArgs)state; @@ -90,6 +109,9 @@ namespace NetSharp.Sockets /// <param name="remoteEndPoint"> /// The remote end point which to which to connect the client. /// </param> + /// <param name="cancellationToken"> + /// The cancellation token to observe during the asynchronous operation. + /// </param> /// <returns> /// A <see cref="ValueTask" /> representing the connection attempt. /// </returns> @@ -102,21 +124,28 @@ namespace NetSharp.Sockets args.RemoteEndPoint = remoteEndPoint; args.UserToken = new AsyncOperationToken(in tcs, in cancellationToken); - // TODO find out why the fricc we leak memory - CancellationTokenRegistration cancellationRegistration = - cancellationToken.Register(CancelAsyncOperationCallback, args); + if (cancellationToken == default) + { + if (Connection.ConnectAsync(args)) return new ValueTask(tcs.Task); + } + else + { + // TODO find out why the fricc we leak memory + CancellationTokenRegistration cancellationRegistration = + cancellationToken.Register(CancelAsyncOperationCallback, args); - if (Connection.ConnectAsync(args)) - return new ValueTask( - tcs.Task.ContinueWith((task, state) => - { - ((CancellationTokenRegistration)state).Dispose(); + if (Connection.ConnectAsync(args)) + return new ValueTask( + tcs.Task.ContinueWith((task, state) => + { + ((CancellationTokenRegistration)state).Dispose(); - return task.Result; - }, cancellationRegistration, CancellationToken.None) - ); + return task.Result; + }, cancellationRegistration, CancellationToken.None) + ); - cancellationRegistration.Dispose(); + cancellationRegistration.Dispose(); + } TransmissionArgsPool.Return(args); @@ -124,6 +153,89 @@ namespace NetSharp.Sockets } /// <summary> + /// Listens for data from the specified endpoint, placing the data in the given buffer. On connection-oriented protocols, the given endpoint + /// is ignored in favour of the default remote host set up by a call to <see cref="Connect" /> or <see cref="ConnectAsync" />. + /// </summary> + /// <param name="remoteEndPoint"> + /// The remote endpoint from which data should be received. Ignored on connection-oriented protocols. + /// </param> + /// <param name="receiveBuffer"> + /// The buffer into which data is to be received. + /// </param> + /// <param name="flags"> + /// The socket flags associated with the send operation. + /// </param> + /// <returns> + /// The result of the receive operation. + /// </returns> + public abstract TransmissionResult Receive(in EndPoint remoteEndPoint, byte[] receiveBuffer, + SocketFlags flags = SocketFlags.None); + + /// <summary> + /// Asynchronously listens for data from the specified endpoint, placing the data in the given buffer. On connection-oriented protocols, the + /// given endpoint is ignored in favour of the default remote host set up by a call to <see cref="Connect" /> or <see cref="ConnectAsync" />. + /// </summary> + /// <param name="remoteEndPoint"> + /// The remote endpoint from which data should be received. Ignored on connection-oriented protocols. + /// </param> + /// <param name="receiveBuffer"> + /// The buffer into which data is to be received. + /// </param> + /// <param name="flags"> + /// The socket flags associated with the send operation. + /// </param> + /// <param name="cancellationToken"> + /// The cancellation token to observe during the asynchronous operation. + /// </param> + /// <returns> + /// The result of the asynchronous receive operation. + /// </returns> + public abstract ValueTask<TransmissionResult> ReceiveAsync(in EndPoint remoteEndPoint, Memory<byte> receiveBuffer, + SocketFlags flags = SocketFlags.None, CancellationToken cancellationToken = default); + + /// <summary> + /// Sends the data in the given buffer to the specified endpoint. On connection-oriented protocols, the given endpoint is ignored in favour of + /// the default remote host set up by a call to <see cref="Connect" /> or <see cref="ConnectAsync" />. + /// </summary> + /// <param name="remoteEndPoint"> + /// The remote endpoint to which data should be sent. Ignored on connection-oriented protocols. + /// </param> + /// <param name="sendBuffer"> + /// The buffer containing the outgoing data to be sent. + /// </param> + /// <param name="flags"> + /// The socket flags associated with the send operation. + /// </param> + /// <returns> + /// The result of the send operation. + /// </returns> + public abstract TransmissionResult Send(in EndPoint remoteEndPoint, byte[] sendBuffer, + SocketFlags flags = SocketFlags.None); + + /// <summary> + /// Asynchronously sends the data in the given buffer to the specified endpoint. On connection-oriented protocols, the given endpoint is + /// ignored in favour of the default remote host set up by a call to <see cref="Connect" /> or <see cref="ConnectAsync" />. + /// </summary> + /// <param name="remoteEndPoint"> + /// The remote endpoint to which data should be sent. Ignored on connection-oriented protocols. + /// </param> + /// <param name="sendBuffer"> + /// The buffer containing the outgoing data to be sent. The contents of the buffer are copied to an internally maintained buffer when the call + /// is made. + /// </param> + /// <param name="flags"> + /// The socket flags associated with the send operation. + /// </param> + /// <param name="cancellationToken"> + /// The cancellation token to observe during the asynchronous operation. + /// </param> + /// <returns> + /// The result of the asynchronous send operation. + /// </returns> + public abstract ValueTask<TransmissionResult> SendAsync(in EndPoint remoteEndPoint, ReadOnlyMemory<byte> sendBuffer, + SocketFlags flags = SocketFlags.None, CancellationToken cancellationToken = default); + + /// <summary> /// A state token for asynchronous socket operations. /// </summary> protected readonly struct AsyncOperationToken @@ -202,6 +314,9 @@ namespace NetSharp.Sockets /// </summary> public readonly TaskCompletionSource<TransmissionResult> CompletionSource; + /// <summary> + /// The rented buffer which holds the user's data. + /// </summary> public readonly byte[] RentedBuffer; /// <summary> @@ -210,6 +325,9 @@ namespace NetSharp.Sockets /// <param name="completionSource"> /// The completion source to trigger when the IO operation completes. /// </param> + /// <param name="rentedBuffer"> + /// The buffer holding the user's data. + /// </param> /// <param name="cancellationToken"> /// The cancellation token to observe during the operation. /// </param> diff --git a/NetSharp/NetSharp/Sockets/Stream/StreamSocketClient.cs b/NetSharp/NetSharp/Sockets/Stream/StreamSocketClient.cs @@ -2,6 +2,7 @@ using NetSharp.Utils; using System; +using System.Net; using System.Net.Sockets; using System.Threading; using System.Threading.Tasks; @@ -278,44 +279,54 @@ namespace NetSharp.Sockets.Stream SocketAsyncEventArgs args = TransmissionArgsPool.Rent(); - args.DisconnectReuseSocket = allowSocketReuse; - args.UserToken = new AsyncOperationToken(in tcs, in cancellationToken); + if (cancellationToken == default) + { + if (Connection.DisconnectAsync(args)) return new ValueTask(tcs.Task); + } + else + { + args.DisconnectReuseSocket = allowSocketReuse; + args.UserToken = new AsyncOperationToken(in tcs, in cancellationToken); - // TODO find out why the fricc we leak memory - CancellationTokenRegistration cancellationRegistration = - cancellationToken.Register(CancelAsyncOperationCallback, args); + // TODO find out why the fricc we leak memory + CancellationTokenRegistration cancellationRegistration = + cancellationToken.Register(CancelAsyncOperationCallback, args); - if (Connection.DisconnectAsync(args)) - return new ValueTask( - tcs.Task.ContinueWith((task, state) => - { - ((CancellationTokenRegistration)state).Dispose(); + if (Connection.DisconnectAsync(args)) + return new ValueTask( + tcs.Task.ContinueWith((task, state) => + { + ((CancellationTokenRegistration)state).Dispose(); - return task.Result; - }, cancellationRegistration, CancellationToken.None) - ); + return task.Result; + }, cancellationRegistration, CancellationToken.None) + ); - cancellationRegistration.Dispose(); + cancellationRegistration.Dispose(); + } TransmissionArgsPool.Return(args); return new ValueTask(); } - public TransmissionResult Receive(byte[] buffer, SocketFlags flags = SocketFlags.None) + /// <inheritdoc /> + public override TransmissionResult Receive(in EndPoint remoteEndPoint, byte[] receiveBuffer, SocketFlags flags = SocketFlags.None) { - int expectedBytes = buffer.Length; + int expectedBytes = receiveBuffer.Length; int receivedBytes = 0; do { - receivedBytes += Connection.Receive(buffer, receivedBytes, expectedBytes - receivedBytes, flags); + receivedBytes += Connection.Receive(receiveBuffer, receivedBytes, expectedBytes - receivedBytes, flags); } while (receivedBytes != 0 && receivedBytes < expectedBytes); - return new TransmissionResult(in buffer, in receivedBytes, Connection.RemoteEndPoint); + return new TransmissionResult(in receiveBuffer, in receivedBytes, Connection.RemoteEndPoint); } - public ValueTask<TransmissionResult> ReceiveAsync(Memory<byte> receiveBuffer, SocketFlags flags = SocketFlags.None, CancellationToken cancellationToken = default) + /// <inheritdoc /> + public override ValueTask<TransmissionResult> ReceiveAsync(in EndPoint remoteEndPoint, Memory<byte> receiveBuffer, SocketFlags flags = SocketFlags.None, + CancellationToken cancellationToken = default) { TaskCompletionSource<TransmissionResult> tcs = new TaskCompletionSource<TransmissionResult>(); @@ -356,20 +367,23 @@ namespace NetSharp.Sockets.Stream return new ValueTask<TransmissionResult>(result); } - public TransmissionResult Send(byte[] buffer, SocketFlags flags = SocketFlags.None) + /// <inheritdoc /> + public override TransmissionResult Send(in EndPoint remoteEndPoint, byte[] sendBuffer, SocketFlags flags = SocketFlags.None) { - int expectedBytes = buffer.Length; + int expectedBytes = sendBuffer.Length; int sentBytes = 0; do { - sentBytes += Connection.Send(buffer, sentBytes, expectedBytes - sentBytes, flags); + sentBytes += Connection.Send(sendBuffer, sentBytes, expectedBytes - sentBytes, flags); } while (sentBytes != 0 && sentBytes < expectedBytes); - return new TransmissionResult(in buffer, in sentBytes, Connection.RemoteEndPoint); + return new TransmissionResult(in sendBuffer, in sentBytes, Connection.RemoteEndPoint); } - public ValueTask<TransmissionResult> SendAsync(ReadOnlyMemory<byte> sendBuffer, SocketFlags flags = SocketFlags.None, CancellationToken cancellationToken = default) + /// <inheritdoc /> + public override ValueTask<TransmissionResult> SendAsync(in EndPoint remoteEndPoint, ReadOnlyMemory<byte> sendBuffer, SocketFlags flags = SocketFlags.None, + CancellationToken cancellationToken = default) { TaskCompletionSource<TransmissionResult> tcs = new TaskCompletionSource<TransmissionResult>(); diff --git a/NetSharp/NetSharpExamples/Benchmarks/TcpSocketClientAsyncBenchmark.cs b/NetSharp/NetSharpExamples/Benchmarks/TcpSocketClientAsyncBenchmark.cs @@ -97,9 +97,9 @@ namespace NetSharpExamples.Benchmarks benchmarkHelper.StartBandwidthStopwatch(); benchmarkHelper.StartRttStopwatch(); - TransmissionResult sendResult = await client.SendAsync(sendBuffer); + TransmissionResult sendResult = await client.SendAsync(in ServerEndPoint, sendBuffer); - TransmissionResult receiveResult = await client.ReceiveAsync(receiveBuffer); + TransmissionResult receiveResult = await client.ReceiveAsync(in ServerEndPoint, receiveBuffer); benchmarkHelper.StopRttStopwatch(); benchmarkHelper.StopBandwidthStopwatch(); diff --git a/NetSharp/NetSharpExamples/Benchmarks/TcpSocketClientSyncBenchmark.cs b/NetSharp/NetSharpExamples/Benchmarks/TcpSocketClientSyncBenchmark.cs @@ -97,9 +97,9 @@ namespace NetSharpExamples.Benchmarks benchmarkHelper.StartBandwidthStopwatch(); benchmarkHelper.StartRttStopwatch(); - TransmissionResult sendResult = client.Send(sendBuffer); + TransmissionResult sendResult = client.Send(in ServerEndPoint, sendBuffer); - TransmissionResult receiveResult = client.Receive(receiveBuffer); + TransmissionResult receiveResult = client.Receive(in ServerEndPoint, receiveBuffer); benchmarkHelper.StopRttStopwatch(); benchmarkHelper.StopBandwidthStopwatch(); diff --git a/NetSharp/NetSharpExamples/Benchmarks/UdpSocketClientAsyncBenchmark.cs b/NetSharp/NetSharpExamples/Benchmarks/UdpSocketClientAsyncBenchmark.cs @@ -73,9 +73,9 @@ namespace NetSharpExamples.Benchmarks benchmarkHelper.StartBandwidthStopwatch(); benchmarkHelper.StartRttStopwatch(); - TransmissionResult sendResult = await client.SendToAsync(ServerEndPoint, sendBuffer); + TransmissionResult sendResult = await client.SendAsync(in ServerEndPoint, sendBuffer); - TransmissionResult receiveResult = await client.ReceiveFromAsync(ServerEndPoint, receiveBuffer); + TransmissionResult receiveResult = await client.ReceiveAsync(in ServerEndPoint, receiveBuffer); benchmarkHelper.StopRttStopwatch(); benchmarkHelper.StopBandwidthStopwatch(); diff --git a/NetSharp/NetSharpExamples/Benchmarks/UdpSocketClientSyncBenchmark.cs b/NetSharp/NetSharpExamples/Benchmarks/UdpSocketClientSyncBenchmark.cs @@ -75,9 +75,9 @@ namespace NetSharpExamples.Benchmarks benchmarkHelper.StartBandwidthStopwatch(); benchmarkHelper.StartRttStopwatch(); - TransmissionResult sendResult = client.SendTo(remoteEndPoint, sendBuffer); + TransmissionResult sendResult = client.Send(in remoteEndPoint, sendBuffer); - TransmissionResult receiveResult = client.ReceiveFrom(ref remoteEndPoint, receiveBuffer); + TransmissionResult receiveResult = client.Receive(in remoteEndPoint, receiveBuffer); benchmarkHelper.StopRttStopwatch(); benchmarkHelper.StopBandwidthStopwatch(); diff --git a/NetSharp/NetSharpExamples/Examples/TcpSocketClientExample.cs b/NetSharp/NetSharpExamples/Examples/TcpSocketClientExample.cs @@ -42,7 +42,7 @@ namespace NetSharpExamples.Examples dataEncoding.GetBytes(data).CopyTo(sendBuffer, 0); TransmissionResult sendResult = - client.Send(sendBuffer, SocketFlags.None); + client.Send(in remoteEndPoint, sendBuffer, SocketFlags.None); /* a cancellable asynchronous version also exists. use only when necessary due to the inherent performance penalty of async operations TransmissionResult sendResult = @@ -56,7 +56,7 @@ namespace NetSharpExamples.Examples } TransmissionResult receiveResult = - client.Receive(receiveBuffer, SocketFlags.None); + client.Receive(in remoteEndPoint, receiveBuffer, SocketFlags.None); /* a cancellable asynchronous version also exists. use only when necessary due to the inherent performance penalty of async operations TransmissionResult receiveResult = diff --git a/NetSharp/NetSharpExamples/Examples/UdpSocketClientCancellationExample.cs b/NetSharp/NetSharpExamples/Examples/UdpSocketClientCancellationExample.cs @@ -69,7 +69,7 @@ namespace NetSharpExamples.Examples using CancellationTokenSource receiveCts = new CancellationTokenSource(); sendCts.CancelAfter(timeout); - TransmissionResult sendResult = await client.SendToAsync(remoteEndPoint, sendBuffer, SocketFlags.None, sendCts.Token); + TransmissionResult sendResult = await client.SendAsync(remoteEndPoint, sendBuffer, SocketFlags.None, sendCts.Token); if (sendResult.TimedOut()) { @@ -80,7 +80,7 @@ namespace NetSharpExamples.Examples Console.WriteLine($"Sent {sendResult.Count} bytes of data!"); receiveCts.CancelAfter(timeout); - TransmissionResult receiveResult = await client.ReceiveFromAsync(remoteEndPoint, receiveBuffer, SocketFlags.None, receiveCts.Token); + TransmissionResult receiveResult = await client.ReceiveAsync(remoteEndPoint, receiveBuffer, SocketFlags.None, receiveCts.Token); if (receiveResult.TimedOut()) { diff --git a/NetSharp/NetSharpExamples/Examples/UdpSocketClientExample.cs b/NetSharp/NetSharpExamples/Examples/UdpSocketClientExample.cs @@ -35,12 +35,11 @@ namespace NetSharpExamples.Examples string data = $"Hello World from {client.LocalEndPoint}!"; dataEncoding.GetBytes(data).CopyTo(sendBuffer, 0); - TransmissionResult sendResult = - client.SendTo(remoteEndPoint, sendBuffer, SocketFlags.None); + TransmissionResult sendResult = client.Send(in remoteEndPoint, sendBuffer, SocketFlags.None); /* a cancellable asynchronous version also exists. use only when necessary due to the inherent performance penalty of async operations TransmissionResult sendResult = - await client.SendToAsync(remoteEndPoint, sendBuffer, SocketFlags.None, CancellationToken.None); + await client.SendAsync(in remoteEndPoint, sendBuffer, SocketFlags.None, CancellationToken.None); */ // lock is not necessary, but means that console output is clean and not interleaved @@ -49,12 +48,12 @@ namespace NetSharpExamples.Examples Console.WriteLine($"[Client] Sent request with contents \'{data}\' to {remoteEndPoint}"); } - TransmissionResult receiveResult = - client.ReceiveFrom(ref remoteEndPoint, receiveBuffer, SocketFlags.None); + TransmissionResult receiveResult = client.Receive(in remoteEndPoint, receiveBuffer, SocketFlags.None); + remoteEndPoint = receiveResult.RemoteEndPoint; /* a cancellable asynchronous version also exists. use only when necessary due to the inherent performance penalty of async operations TransmissionResult receiveResult = - await client.ReceiveFromAsync(remoteEndPoint, receiveBuffer, SocketFlags.None, CancellationToken.None); + await client.ReceiveAsync(in remoteEndPoint, receiveBuffer, SocketFlags.None, CancellationToken.None); */ // lock is not necessary, but means that console output is clean and not interleaved