commit 7545617da2caa6168b44bf53b5e4873dc01ae6c4
parent 99fba2a642114c8a22cfe50f8a7d097cd885f47a
Author: Mikolaj Lenczewski <mikolaj.lenczewski308@gmail.com>
Date: Thu, 30 Apr 2020 17:10:05 +0100
Restructuring again because im a masochist! (maybe stuff wont be as hard this time!)
Diffstat:
31 files changed, 1467 insertions(+), 1171 deletions(-)
diff --git a/NetSharp/NetSharp/DatagramNetworkConnection.cs b/NetSharp/NetSharp/DatagramNetworkConnection.cs
@@ -0,0 +1,204 @@
+using System;
+using System.Net;
+using System.Net.Sockets;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace NetSharp
+{
+ public sealed class DatagramNetworkReader : NetworkReaderBase<SocketAsyncEventArgs>
+ {
+ /// <inheritdoc />
+ public DatagramNetworkReader(ref Socket rawConnection, NetworkRequestHandler? requestHandler, EndPoint defaultEndPoint, int maxPooledBufferSize, int preallocatedStateObjects = 0)
+ : base(ref rawConnection, requestHandler, defaultEndPoint, maxPooledBufferSize, preallocatedStateObjects)
+ {
+ }
+
+ private void CompleteReceiveFrom(SocketAsyncEventArgs args)
+ {
+ RentedBufferHandle receiveBufferHandle = (RentedBufferHandle) args.UserToken;
+
+ switch (args.SocketError)
+ {
+ case SocketError.Success:
+ RentedBufferHandle responseBufferHandle = RentBuffer(BufferSize);
+
+ bool responseExists =
+ RequestHandler(args.RemoteEndPoint, receiveBufferHandle.RentedBuffer, responseBufferHandle.RentedBuffer);
+ ReturnBuffer(receiveBufferHandle);
+
+ if (responseExists)
+ {
+ args.SetBuffer(responseBufferHandle.RentedBuffer);
+ args.UserToken = responseBufferHandle;
+
+ StartSendTo(args);
+
+ return;
+ }
+
+ ReturnBuffer(responseBufferHandle);
+ break;
+
+ default:
+ ReturnBuffer(receiveBufferHandle);
+ StateObjectPool.Return(args);
+ break;
+ }
+ }
+
+ private void CompleteSendTo(SocketAsyncEventArgs args)
+ {
+ RentedBufferHandle sendBufferHandle = (RentedBufferHandle)args.UserToken;
+
+ ReturnBuffer(sendBufferHandle);
+ StateObjectPool.Return(args);
+ }
+
+ private void HandleIoCompleted(object sender, SocketAsyncEventArgs args)
+ {
+ switch (args.LastOperation)
+ {
+ case SocketAsyncOperation.ReceiveFrom:
+ StartDefaultReceiveFrom();
+
+ CompleteReceiveFrom(args);
+ break;
+
+ case SocketAsyncOperation.SendTo:
+ CompleteSendTo(args);
+ break;
+ }
+ }
+
+ private void StartDefaultReceiveFrom()
+ {
+ if (ShutdownToken.IsCancellationRequested)
+ {
+ return;
+ }
+
+ SocketAsyncEventArgs args = StateObjectPool.Rent();
+ StartReceiveFrom(args);
+ }
+
+ private void StartReceiveFrom(SocketAsyncEventArgs args)
+ {
+ RentedBufferHandle receiveBufferHandle = RentBuffer(BufferSize);
+
+ args.SetBuffer(receiveBufferHandle.RentedBuffer, 0, BufferSize);
+ args.UserToken = receiveBufferHandle;
+
+ if (ShutdownToken.IsCancellationRequested)
+ {
+ ReturnBuffer(receiveBufferHandle);
+ StateObjectPool.Return(args);
+
+ return;
+ }
+
+ if (Connection.ReceiveFromAsync(args)) return;
+
+ StartDefaultReceiveFrom();
+ CompleteReceiveFrom(args);
+ }
+
+ private void StartSendTo(SocketAsyncEventArgs args)
+ {
+ RentedBufferHandle sendBufferHandle = (RentedBufferHandle) args.UserToken;
+
+ if (ShutdownToken.IsCancellationRequested)
+ {
+ ReturnBuffer(sendBufferHandle);
+ StateObjectPool.Return(args);
+
+ return;
+ }
+
+ if (Connection.SendToAsync(args)) return;
+
+ CompleteSendTo(args);
+ }
+
+ /// <inheritdoc />
+ protected override bool CanReuseStateObject(in SocketAsyncEventArgs instance)
+ {
+ return true;
+ }
+
+ /// <inheritdoc />
+ protected override SocketAsyncEventArgs CreateStateObject()
+ {
+ SocketAsyncEventArgs instance = new SocketAsyncEventArgs { RemoteEndPoint = DefaultEndPoint };
+ instance.Completed += HandleIoCompleted;
+
+ return instance;
+ }
+
+ /// <inheritdoc />
+ protected override void DestroyStateObject(SocketAsyncEventArgs instance)
+ {
+ instance.Completed -= HandleIoCompleted;
+ instance.Dispose();
+ }
+
+ /// <inheritdoc />
+ protected override void ResetStateObject(ref SocketAsyncEventArgs instance)
+ {
+ instance.RemoteEndPoint = DefaultEndPoint;
+ }
+
+ /// <inheritdoc />
+ public override void Start(ushort concurrentReadTasks)
+ {
+ for (ushort i = 0; i < concurrentReadTasks; i++)
+ {
+ StartDefaultReceiveFrom();
+ }
+ }
+ }
+
+ public sealed class DatagramNetworkWriter : NetworkWriterBase<SocketAsyncEventArgs>
+ {
+ /// <inheritdoc />
+ public DatagramNetworkWriter(ref Socket rawConnection, int maxPooledBufferSize, int preallocatedStateObjects = 0) : base(ref rawConnection, maxPooledBufferSize, preallocatedStateObjects)
+ {
+ }
+
+ /// <inheritdoc />
+ protected override bool CanReuseStateObject(in SocketAsyncEventArgs instance)
+ {
+ throw new NotImplementedException();
+ }
+
+ /// <inheritdoc />
+ protected override SocketAsyncEventArgs CreateStateObject()
+ {
+ throw new NotImplementedException();
+ }
+
+ /// <inheritdoc />
+ protected override void DestroyStateObject(SocketAsyncEventArgs instance)
+ {
+ throw new NotImplementedException();
+ }
+
+ /// <inheritdoc />
+ protected override void ResetStateObject(ref SocketAsyncEventArgs instance)
+ {
+ throw new NotImplementedException();
+ }
+
+ /// <inheritdoc />
+ public override int Write(EndPoint remoteEndPoint, ReadOnlyMemory<byte> writeBuffer, SocketFlags flags = SocketFlags.None)
+ {
+ throw new NotImplementedException();
+ }
+
+ /// <inheritdoc />
+ public override ValueTask<int> WriteAsync(EndPoint remoteEndPoint, ReadOnlyMemory<byte> writeBuffer, SocketFlags flags = SocketFlags.None)
+ {
+ throw new NotImplementedException();
+ }
+ }
+}
+\ No newline at end of file
diff --git a/NetSharp/NetSharp/NetSharp.xml b/NetSharp/NetSharp/NetSharp.xml
@@ -4,6 +4,62 @@
<name>NetSharp</name>
</assembly>
<members>
+ <member name="M:NetSharp.DatagramNetworkReader.#ctor(System.Net.Sockets.Socket@,NetSharp.NetworkRequestHandler,System.Net.EndPoint,System.Int32,System.Int32)">
+ <inheritdoc />
+ </member>
+ <member name="M:NetSharp.DatagramNetworkReader.CanReuseStateObject(System.Net.Sockets.SocketAsyncEventArgs@)">
+ <inheritdoc />
+ </member>
+ <member name="M:NetSharp.DatagramNetworkReader.CreateStateObject">
+ <inheritdoc />
+ </member>
+ <member name="M:NetSharp.DatagramNetworkReader.DestroyStateObject(System.Net.Sockets.SocketAsyncEventArgs)">
+ <inheritdoc />
+ </member>
+ <member name="M:NetSharp.DatagramNetworkReader.ResetStateObject(System.Net.Sockets.SocketAsyncEventArgs@)">
+ <inheritdoc />
+ </member>
+ <member name="M:NetSharp.DatagramNetworkReader.Start(System.UInt16)">
+ <inheritdoc />
+ </member>
+ <member name="M:NetSharp.DatagramNetworkWriter.#ctor(System.Net.Sockets.Socket@,System.Int32,System.Int32)">
+ <inheritdoc />
+ </member>
+ <member name="M:NetSharp.DatagramNetworkWriter.CanReuseStateObject(System.Net.Sockets.SocketAsyncEventArgs@)">
+ <inheritdoc />
+ </member>
+ <member name="M:NetSharp.DatagramNetworkWriter.CreateStateObject">
+ <inheritdoc />
+ </member>
+ <member name="M:NetSharp.DatagramNetworkWriter.DestroyStateObject(System.Net.Sockets.SocketAsyncEventArgs)">
+ <inheritdoc />
+ </member>
+ <member name="M:NetSharp.DatagramNetworkWriter.ResetStateObject(System.Net.Sockets.SocketAsyncEventArgs@)">
+ <inheritdoc />
+ </member>
+ <member name="M:NetSharp.DatagramNetworkWriter.Write(System.Net.EndPoint,System.ReadOnlyMemory{System.Byte},System.Net.Sockets.SocketFlags)">
+ <inheritdoc />
+ </member>
+ <member name="M:NetSharp.DatagramNetworkWriter.WriteAsync(System.Net.EndPoint,System.ReadOnlyMemory{System.Byte},System.Net.Sockets.SocketFlags)">
+ <inheritdoc />
+ </member>
+ <member name="M:NetSharp.NetworkConnectionBase`1.Dispose(System.Boolean)">
+ <summary>
+ Allows for inheritors to dispose of their own resources.
+ </summary>
+ </member>
+ <member name="M:NetSharp.NetworkConnectionBase`1.Dispose">
+ <inheritdoc />
+ </member>
+ <member name="M:NetSharp.NetworkReaderBase`1.#ctor(System.Net.Sockets.Socket@,NetSharp.NetworkRequestHandler,System.Net.EndPoint,System.Int32,System.Int32)">
+ <inheritdoc />
+ </member>
+ <member name="M:NetSharp.NetworkReaderBase`1.Dispose(System.Boolean)">
+ <inheritdoc />
+ </member>
+ <member name="M:NetSharp.NetworkWriterBase`1.#ctor(System.Net.Sockets.Socket@,System.Int32,System.Int32)">
+ <inheritdoc />
+ </member>
<member name="T:NetSharp.Packets.NetworkPacket">
<summary>
Represents a raw packet sent across the network.
@@ -192,19 +248,19 @@
<member name="M:NetSharp.Sockets.Datagram.DatagramSocketClient.HandleIoCompleted(System.Object,System.Net.Sockets.SocketAsyncEventArgs)">
<inheritdoc />
</member>
- <member name="M:NetSharp.Sockets.Datagram.DatagramSocketClient.ResetTransmissionArgs(System.Net.Sockets.SocketAsyncEventArgs)">
+ <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)">
+ <member name="M:NetSharp.Sockets.Datagram.DatagramSocketClient.ReceiveAsync(System.Net.EndPoint@,System.Memory{System.Byte},System.Net.Sockets.SocketFlags)">
<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)">
+ <member name="M:NetSharp.Sockets.Datagram.DatagramSocketClient.SendAsync(System.Net.EndPoint@,System.ReadOnlyMemory{System.Byte},System.Net.Sockets.SocketFlags)">
<inheritdoc />
</member>
<member name="T:NetSharp.Sockets.Datagram.DatagramSocketServerOptions">
@@ -240,7 +296,7 @@
The number of <see cref="T:System.Net.Sockets.SocketAsyncEventArgs" /> instances to preallocate.
</param>
</member>
- <member name="M:NetSharp.Sockets.Datagram.DatagramSocketServer.#ctor(System.Net.Sockets.AddressFamily@,System.Net.Sockets.ProtocolType@,NetSharp.Sockets.SocketServerPacketHandler@,System.Nullable{NetSharp.Sockets.Datagram.DatagramSocketServerOptions}@)">
+ <member name="M:NetSharp.Sockets.Datagram.DatagramSocketServer.#ctor(System.Net.Sockets.Socket@,NetSharp.Sockets.RawRequestPacketHandler@,System.Nullable{NetSharp.Sockets.Datagram.DatagramSocketServerOptions}@)">
<summary>
Constructs a new instance of the <see cref="T:NetSharp.Sockets.Datagram.DatagramSocketServer" /> class.
</summary>
@@ -261,30 +317,24 @@
<member name="M:NetSharp.Sockets.Datagram.DatagramSocketServer.HandleIoCompleted(System.Object,System.Net.Sockets.SocketAsyncEventArgs)">
<inheritdoc />
</member>
- <member name="M:NetSharp.Sockets.Datagram.DatagramSocketServer.ResetTransmissionArgs(System.Net.Sockets.SocketAsyncEventArgs)">
+ <member name="M:NetSharp.Sockets.Datagram.DatagramSocketServer.ResetTransmissionArgs(System.Net.Sockets.SocketAsyncEventArgs@)">
<inheritdoc />
</member>
<member name="M:NetSharp.Sockets.Datagram.DatagramSocketServer.RunAsync(System.Threading.CancellationToken)">
<inheritdoc />
</member>
- <member name="T:NetSharp.Sockets.SocketClient">
+ <member name="T:NetSharp.Sockets.RawSocketClient">
<summary>
Abstract base class for clients.
</summary>
TODO implement proper memory leak-free cancellation of network IO operations
</member>
- <member name="M:NetSharp.Sockets.SocketClient.#ctor(System.Net.Sockets.AddressFamily@,System.Net.Sockets.SocketType@,System.Net.Sockets.ProtocolType@,System.Int32@,System.UInt16@)">
+ <member name="M:NetSharp.Sockets.RawSocketClient.#ctor(System.Net.Sockets.Socket@,System.Int32,System.UInt16)">
<summary>
- Constructs a new instance of the <see cref="T:NetSharp.Sockets.SocketClient" /> class.
+ Constructs a new instance of the <see cref="T:NetSharp.Sockets.RawSocketClient" /> class.
</summary>
- <param name="connectionAddressFamily">
- The address family that the underlying connection should use.
- </param>
- <param name="connectionSocketType">
- The socket type that the underlying connection should use.
- </param>
- <param name="connectionProtocolType">
- The protocol type that the underlying connection should use.
+ <param name="rawConnection">
+ The underlying <see cref="T:System.Net.Sockets.Socket"/> object which should be wrapped by this instance.
</param>
<param name="pooledBufferMaxSize">
The maximum size in bytes of buffers held in the buffer pool.
@@ -293,7 +343,7 @@
The number of transmission args to preallocate.
</param>
</member>
- <member name="M:NetSharp.Sockets.SocketClient.CancelAsyncOperationCallback(System.Object)">
+ <member name="M:NetSharp.Sockets.RawSocketClient.CancelAsyncOperationCallback(System.Object)">
<summary>
Callback for the cancellation of an asynchronous network operation.
</summary>
@@ -301,7 +351,7 @@
The <see cref="T:System.Net.Sockets.SocketAsyncEventArgs" /> state object for the operation.
</param>
</member>
- <member name="M:NetSharp.Sockets.SocketClient.CancelAsyncReceiveCallback(System.Object)">
+ <member name="M:NetSharp.Sockets.RawSocketClient.CancelAsyncReceiveCallback(System.Object)">
<summary>
Callback for the cancellation of an asynchronous network receive operation.
</summary>
@@ -309,7 +359,7 @@
The <see cref="T:System.Net.Sockets.SocketAsyncEventArgs" /> state object for the operation.
</param>
</member>
- <member name="M:NetSharp.Sockets.SocketClient.CancelAsyncSendCallback(System.Object)">
+ <member name="M:NetSharp.Sockets.RawSocketClient.CancelAsyncSendCallback(System.Object)">
<summary>
Callback for the cancellation of an asynchronous network send operation.
</summary>
@@ -317,7 +367,7 @@
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@)">
+ <member name="M:NetSharp.Sockets.RawSocketClient.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
default remote host, and the client will ignore any packets not coming from this default host (i.e the given <paramref name="remoteEndPoint" />).
@@ -326,7 +376,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.RawSocketClient.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" />).
@@ -334,17 +384,14 @@
<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)">
+ <member name="M:NetSharp.Sockets.RawSocketClient.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)" />.
+ is ignored in favour of the default remote host set up by a call to <see cref="M:NetSharp.Sockets.RawSocketClient.Connect(System.Net.EndPoint@)" /> or <see cref="M:NetSharp.Sockets.RawSocketClient.ConnectAsync(System.Net.EndPoint@)" />.
</summary>
<param name="remoteEndPoint">
The remote endpoint from which data should be received. Ignored on connection-oriented protocols.
@@ -359,10 +406,10 @@
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)">
+ <member name="M:NetSharp.Sockets.RawSocketClient.ReceiveAsync(System.Net.EndPoint@,System.Memory{System.Byte},System.Net.Sockets.SocketFlags)">
<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)" />.
+ given endpoint is ignored in favour of the default remote host set up by a call to <see cref="M:NetSharp.Sockets.RawSocketClient.Connect(System.Net.EndPoint@)" /> or <see cref="M:NetSharp.Sockets.RawSocketClient.ConnectAsync(System.Net.EndPoint@)" />.
</summary>
<param name="remoteEndPoint">
The remote endpoint from which data should be received. Ignored on connection-oriented protocols.
@@ -373,17 +420,14 @@
<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)">
+ <member name="M:NetSharp.Sockets.RawSocketClient.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)" />.
+ the default remote host set up by a call to <see cref="M:NetSharp.Sockets.RawSocketClient.Connect(System.Net.EndPoint@)" /> or <see cref="M:NetSharp.Sockets.RawSocketClient.ConnectAsync(System.Net.EndPoint@)" />.
</summary>
<param name="remoteEndPoint">
The remote endpoint to which data should be sent. Ignored on connection-oriented protocols.
@@ -398,10 +442,10 @@
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)">
+ <member name="M:NetSharp.Sockets.RawSocketClient.SendAsync(System.Net.EndPoint@,System.ReadOnlyMemory{System.Byte},System.Net.Sockets.SocketFlags)">
<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)" />.
+ ignored in favour of the default remote host set up by a call to <see cref="M:NetSharp.Sockets.RawSocketClient.Connect(System.Net.EndPoint@)" /> or <see cref="M:NetSharp.Sockets.RawSocketClient.ConnectAsync(System.Net.EndPoint@)" />.
</summary>
<param name="remoteEndPoint">
The remote endpoint to which data should be sent. Ignored on connection-oriented protocols.
@@ -413,31 +457,28 @@
<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">
+ <member name="T:NetSharp.Sockets.RawSocketClient.AsyncOperationToken">
<summary>
A state token for asynchronous socket operations.
</summary>
</member>
- <member name="F:NetSharp.Sockets.SocketClient.AsyncOperationToken.CancellationToken">
+ <member name="F:NetSharp.Sockets.RawSocketClient.AsyncOperationToken.CancellationToken">
<summary>
The <see cref="T:System.Threading.CancellationToken" /> associated with the socket operation.
</summary>
</member>
- <member name="F:NetSharp.Sockets.SocketClient.AsyncOperationToken.CompletionSource">
+ <member name="F:NetSharp.Sockets.RawSocketClient.AsyncOperationToken.CompletionSource">
<summary>
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.AsyncOperationToken.#ctor(System.Threading.Tasks.TaskCompletionSource{System.Boolean}@,System.Threading.CancellationToken@)">
+ <member name="M:NetSharp.Sockets.RawSocketClient.AsyncOperationToken.#ctor(System.Threading.Tasks.TaskCompletionSource{System.Boolean}@,System.Threading.CancellationToken@)">
<summary>
- Constructs a new instance of the <see cref="T:NetSharp.Sockets.SocketClient.AsyncOperationToken" /> struct.
+ Constructs a new instance of the <see cref="T:NetSharp.Sockets.RawSocketClient.AsyncOperationToken" /> struct.
</summary>
<param name="completionSource">
The completion source to trigger when the socket operation completes.
@@ -446,24 +487,24 @@
The cancellation token to observe during the operation.
</param>
</member>
- <member name="T:NetSharp.Sockets.SocketClient.AsyncReceiveToken">
+ <member name="T:NetSharp.Sockets.RawSocketClient.AsyncReceiveToken">
<summary>
A state token for asynchronous incoming network IO operations.
</summary>
</member>
- <member name="F:NetSharp.Sockets.SocketClient.AsyncReceiveToken.CancellationToken">
+ <member name="F:NetSharp.Sockets.RawSocketClient.AsyncReceiveToken.CancellationToken">
<summary>
The <see cref="T:System.Threading.CancellationToken" /> associated with the network IO operation.
</summary>
</member>
- <member name="F:NetSharp.Sockets.SocketClient.AsyncReceiveToken.CompletionSource">
+ <member name="F:NetSharp.Sockets.RawSocketClient.AsyncReceiveToken.CompletionSource">
<summary>
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.AsyncReceiveToken.#ctor(System.Threading.Tasks.TaskCompletionSource{NetSharp.Utils.TransmissionResult}@,System.Threading.CancellationToken@)">
+ <member name="M:NetSharp.Sockets.RawSocketClient.AsyncReceiveToken.#ctor(System.Threading.Tasks.TaskCompletionSource{NetSharp.Utils.TransmissionResult}@,System.Threading.CancellationToken@)">
<summary>
- Constructs a new instance of the <see cref="T:NetSharp.Sockets.SocketClient.AsyncReceiveToken" /> struct.
+ Constructs a new instance of the <see cref="T:NetSharp.Sockets.RawSocketClient.AsyncReceiveToken" /> struct.
</summary>
<param name="completionSource">
The completion source to trigger when the IO operation completes.
@@ -472,73 +513,140 @@
The cancellation token to observe during the operation.
</param>
</member>
- <member name="T:NetSharp.Sockets.SocketClient.AsyncSendToken">
+ <member name="T:NetSharp.Sockets.RawSocketClient.AsyncSendToken">
<summary>
A state token for asynchronous outgoing network IO operations.
</summary>
</member>
- <member name="F:NetSharp.Sockets.SocketClient.AsyncSendToken.CancellationToken">
+ <member name="F:NetSharp.Sockets.RawSocketClient.AsyncSendToken.CancellationToken">
<summary>
The <see cref="T:System.Threading.CancellationToken" /> associated with the network IO operation.
</summary>
</member>
- <member name="F:NetSharp.Sockets.SocketClient.AsyncSendToken.CompletionSource">
+ <member name="F:NetSharp.Sockets.RawSocketClient.AsyncSendToken.CompletionSource">
<summary>
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">
+ <member name="F:NetSharp.Sockets.RawSocketClient.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@)">
+ <member name="M:NetSharp.Sockets.RawSocketClient.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.
+ Constructs a new instance of the <see cref="T:NetSharp.Sockets.RawSocketClient.AsyncSendToken" /> struct.
</summary>
<param name="completionSource">
The completion source to trigger when the IO operation completes.
</param>
- <param name="rentedBuffer">
+ <param name="bufferHandle">
The buffer holding the user's data.
</param>
<param name="cancellationToken">
The cancellation token to observe during the operation.
</param>
</member>
- <member name="T:NetSharp.Sockets.SocketConnection">
+ <member name="T:NetSharp.Sockets.RawRequestPacketHandler">
+ <summary>
+ Represents a method for serving request packets. This method should not throw any errors.
+ </summary>
+ <param name="clientEndPoint">
+ The client from which the packet was received.
+ </param>
+ <param name="requestBuffer">
+ The buffer holding the data received from the client.
+ </param>
+ <param name="responseBuffer">
+ The buffer into which the optional response should be written.
+ </param>
+ <returns>
+ Whether a response was generated which should be sent back to the client.
+ </returns>
+ </member>
+ <member name="T:NetSharp.Sockets.RawSocketServer">
+ <summary>
+ Abstract base class for servers.
+ </summary>
+ </member>
+ <member name="F:NetSharp.Sockets.RawSocketServer.PacketHandler">
+ <summary>
+ The packet handler delegate to use to respond to incoming requests.
+ </summary>
+ </member>
+ <member name="M:NetSharp.Sockets.RawSocketServer.#ctor(System.Net.Sockets.Socket@,System.Int32,System.UInt16,NetSharp.Sockets.RawRequestPacketHandler)">
+ <summary>
+ Constructs a new instance of the <see cref="T:NetSharp.Sockets.RawSocketServer" /> class.
+ </summary>
+ <param name="rawConnection">
+ The underlying <see cref="T:System.Net.Sockets.Socket"/> object which should be wrapped by this instance.
+ </param>
+ <param name="packetHandler">
+ The packet handler delegate to use to respond to incoming requests.
+ </param>
+ <param name="pooledBufferMaxSize">
+ The maximum size in bytes of buffers held in the buffer pool.
+ </param>
+ <param name="preallocatedTransmissionArgs">
+ The number of transmission args to preallocate.
+ </param>
+ </member>
+ <member name="M:NetSharp.Sockets.RawSocketServer.DefaultRawPacketHandler(System.Net.EndPoint@,System.ReadOnlyMemory{System.Byte},System.Memory{System.Byte})">
+ <summary>
+ The default request handler for servers. Simply echoes back any received data.
+ </summary>
+ <param name="remoteEndPoint">
+ The client from which the packet was received.
+ </param>
+ <param name="requestBuffer">The data that was received.</param>
+ <param name="responseBuffer">The data that should be sent back.</param>
+ <returns>
+ Whether to send back a response.
+ </returns>
+ </member>
+ <member name="M:NetSharp.Sockets.RawSocketServer.RunAsync(System.Threading.CancellationToken)">
+ <summary>
+ Runs the server, handling requests from clients, until the <paramref name="cancellationToken" /> has its cancellation requested.
+ </summary>
+ <param name="cancellationToken">
+ The <see cref="T:System.Threading.CancellationToken" /> upon whose cancellation the server should shut down.
+ </param>
+ <returns>
+ A <see cref="T:System.Threading.Tasks.Task" /> representing the server's execution.
+ </returns>
+ </member>
+ <member name="T:NetSharp.Sockets.SocketConnectionBase">
<summary>
- Abstract base class for clients and servers.
+ Abstract base class for client and server wrappers around existing <see cref="T:System.Net.Sockets.Socket"/> objects.
</summary>
</member>
- <member name="F:NetSharp.Sockets.SocketConnection.BufferPool">
+ <member name="F:NetSharp.Sockets.SocketConnectionBase.MaxBufferSize">
+ <summary>
+ The maximum size of buffer that can be rented from the pool.
+ </summary>
+ </member>
+ <member name="F:NetSharp.Sockets.SocketConnectionBase.BufferPool">
<summary>
Pools arrays to function as temporary buffers during network read/write operations.
</summary>
</member>
- <member name="F:NetSharp.Sockets.SocketConnection.TransmissionArgsPool">
+ <member name="F:NetSharp.Sockets.SocketConnectionBase.ArgsPool">
<summary>
Pools <see cref="T:System.Net.Sockets.SocketAsyncEventArgs" /> objects for use during network read/write operations and calls to
<see cref="T:System.Net.Sockets.Socket" />.XXXAsync( <see cref="T:System.Net.Sockets.SocketAsyncEventArgs" />) methods.
</summary>
</member>
- <member name="F:NetSharp.Sockets.SocketConnection.Connection">
+ <member name="F:NetSharp.Sockets.SocketConnectionBase.Connection">
<summary>
The underlying <see cref="T:System.Net.Sockets.Socket" /> which provides access to network operations.
</summary>
</member>
- <member name="M:NetSharp.Sockets.SocketConnection.#ctor(System.Net.Sockets.AddressFamily@,System.Net.Sockets.SocketType@,System.Net.Sockets.ProtocolType@,System.Int32@,System.UInt16@)">
+ <member name="M:NetSharp.Sockets.SocketConnectionBase.#ctor(System.Net.Sockets.Socket@,System.Int32,System.UInt16)">
<summary>
- Constructs a new instance of the <see cref="T:NetSharp.Sockets.SocketConnection" /> class.
+ Constructs a new instance of the <see cref="T:NetSharp.Sockets.SocketConnectionBase" /> class.
</summary>
- <param name="connectionAddressFamily">
- The address family for the underlying socket.
- </param>
- <param name="connectionSocketType">
- The socket type for the underlying socket.
- </param>
- <param name="connectionProtocolType">
- The protocol type for the underlying socket.
+ <param name="rawConnection">
+ The underlying <see cref="T:System.Net.Sockets.Socket"/> object which should be wrapped by this instance.
</param>
<param name="pooledBufferMaxSize">
The maximum size in bytes of buffers held in the buffer pool.
@@ -547,16 +655,16 @@
The number of <see cref="T:System.Net.Sockets.SocketAsyncEventArgs" /> objects to initially preallocate.
</param>
</member>
- <member name="P:NetSharp.Sockets.SocketConnection.LocalEndPoint">
+ <member name="P:NetSharp.Sockets.SocketConnectionBase.LocalEndPoint">
<summary>
The local endpoint to which the underlying <see cref="T:System.Net.Sockets.Socket" /> is bound.
</summary>
</member>
- <member name="M:NetSharp.Sockets.SocketConnection.CanTransmissionArgsBeReused(System.Net.Sockets.SocketAsyncEventArgs@)">
+ <member name="M:NetSharp.Sockets.SocketConnectionBase.CanTransmissionArgsBeReused(System.Net.Sockets.SocketAsyncEventArgs@)">
<summary>
Delegate method used to check whether the given used <see cref="T:System.Net.Sockets.SocketAsyncEventArgs" /> instance can be reused by the
- <see cref="F:NetSharp.Sockets.SocketConnection.TransmissionArgsPool" />. If this method returns <c>true</c>, <see cref="M:NetSharp.Sockets.SocketConnection.ResetTransmissionArgs(System.Net.Sockets.SocketAsyncEventArgs)" /> is called on the given
- <paramref name="args" />. Otherwise, <see cref="M:NetSharp.Sockets.SocketConnection.DestroyTransmissionArgs(System.Net.Sockets.SocketAsyncEventArgs)" /> is called.
+ <see cref="F:NetSharp.Sockets.SocketConnectionBase.ArgsPool" />. If this method returns <c>true</c>, <see cref="M:NetSharp.Sockets.SocketConnectionBase.ResetTransmissionArgs(System.Net.Sockets.SocketAsyncEventArgs@)" /> is called on the given
+ <paramref name="args" />. Otherwise, <see cref="M:NetSharp.Sockets.SocketConnectionBase.DestroyTransmissionArgs(System.Net.Sockets.SocketAsyncEventArgs)" /> is called.
</summary>
<param name="args">
The <see cref="T:System.Net.Sockets.SocketAsyncEventArgs" /> instance to check.
@@ -565,35 +673,35 @@
Whether the given <paramref name="args" /> should be reset and reused, or should be destroyed.
</returns>
</member>
- <member name="M:NetSharp.Sockets.SocketConnection.CreateTransmissionArgs">
+ <member name="M:NetSharp.Sockets.SocketConnectionBase.CreateTransmissionArgs">
<summary>
- Delegate method used to construct fresh <see cref="T:System.Net.Sockets.SocketAsyncEventArgs" /> instances for use in the <see cref="F:NetSharp.Sockets.SocketConnection.TransmissionArgsPool" />.
- The resulting instance should register <see cref="M:NetSharp.Sockets.SocketConnection.HandleIoCompleted(System.Object,System.Net.Sockets.SocketAsyncEventArgs)" /> as an event handler for the
+ Delegate method used to construct fresh <see cref="T:System.Net.Sockets.SocketAsyncEventArgs" /> instances for use in the <see cref="F:NetSharp.Sockets.SocketConnectionBase.ArgsPool" />.
+ The resulting instance should register <see cref="M:NetSharp.Sockets.SocketConnectionBase.HandleIoCompleted(System.Object,System.Net.Sockets.SocketAsyncEventArgs)" /> as an event handler for the
<see cref="E:System.Net.Sockets.SocketAsyncEventArgs.Completed" /> event.
</summary>
<returns>
The configured <see cref="T:System.Net.Sockets.SocketAsyncEventArgs" /> instance.
</returns>
</member>
- <member name="M:NetSharp.Sockets.SocketConnection.DestroyTransmissionArgs(System.Net.Sockets.SocketAsyncEventArgs)">
+ <member name="M:NetSharp.Sockets.SocketConnectionBase.DestroyTransmissionArgs(System.Net.Sockets.SocketAsyncEventArgs)">
<summary>
Delegate method to destroy used <see cref="T:System.Net.Sockets.SocketAsyncEventArgs" /> instances that cannot be reused by the
- <see cref="F:NetSharp.Sockets.SocketConnection.TransmissionArgsPool" />. This method should deregister <see cref="M:NetSharp.Sockets.SocketConnection.HandleIoCompleted(System.Object,System.Net.Sockets.SocketAsyncEventArgs)" /> as an event handler for the
+ <see cref="F:NetSharp.Sockets.SocketConnectionBase.ArgsPool" />. This method should deregister <see cref="M:NetSharp.Sockets.SocketConnectionBase.HandleIoCompleted(System.Object,System.Net.Sockets.SocketAsyncEventArgs)" /> as an event handler for the
<see cref="E:System.Net.Sockets.SocketAsyncEventArgs.Completed" /> event.
</summary>
<param name="remoteConnectionArgs">
The <see cref="T:System.Net.Sockets.SocketAsyncEventArgs" /> which should be destroyed.
</param>
</member>
- <member name="M:NetSharp.Sockets.SocketConnection.Dispose(System.Boolean)">
+ <member name="M:NetSharp.Sockets.SocketConnectionBase.Dispose(System.Boolean)">
<summary>
- Disposes of managed and unmanaged resources used by the <see cref="T:NetSharp.Sockets.SocketConnection" /> class.
+ Disposes of managed and unmanaged resources used by the <see cref="T:NetSharp.Sockets.SocketConnectionBase" /> class.
</summary>
<param name="disposing">
- Whether this call was made by a call to <see cref="M:NetSharp.Sockets.SocketConnection.Dispose" />.
+ Whether this call was made by a call to <see cref="M:NetSharp.Sockets.SocketConnectionBase.Dispose" />.
</param>
</member>
- <member name="M:NetSharp.Sockets.SocketConnection.HandleIoCompleted(System.Object,System.Net.Sockets.SocketAsyncEventArgs)">
+ <member name="M:NetSharp.Sockets.SocketConnectionBase.HandleIoCompleted(System.Object,System.Net.Sockets.SocketAsyncEventArgs)">
<summary>
Delegate method to handle asynchronous network IO completion via the <see cref="E:System.Net.Sockets.SocketAsyncEventArgs.Completed" /> event.
</summary>
@@ -604,15 +712,15 @@
The <see cref="T:System.Net.Sockets.SocketAsyncEventArgs" /> instance associated with the asynchronous network IO.
</param>
</member>
- <member name="M:NetSharp.Sockets.SocketConnection.ResetTransmissionArgs(System.Net.Sockets.SocketAsyncEventArgs)">
+ <member name="M:NetSharp.Sockets.SocketConnectionBase.ResetTransmissionArgs(System.Net.Sockets.SocketAsyncEventArgs@)">
<summary>
- Delegate method used to reset used <see cref="T:System.Net.Sockets.SocketAsyncEventArgs" /> instances for later reuse by the <see cref="F:NetSharp.Sockets.SocketConnection.TransmissionArgsPool" />.
+ Delegate method used to reset used <see cref="T:System.Net.Sockets.SocketAsyncEventArgs" /> instances for later reuse by the <see cref="F:NetSharp.Sockets.SocketConnectionBase.ArgsPool" />.
</summary>
<param name="args">
The <see cref="T:System.Net.Sockets.SocketAsyncEventArgs" /> instance that should be reset.
</param>
</member>
- <member name="M:NetSharp.Sockets.SocketConnection.Bind(System.Net.EndPoint@)">
+ <member name="M:NetSharp.Sockets.SocketConnectionBase.Bind(System.Net.EndPoint@)">
<summary>
Binds the underlying socket.
</summary>
@@ -620,10 +728,10 @@
The end point to which the socket should be bound.
</param>
</member>
- <member name="M:NetSharp.Sockets.SocketConnection.Dispose">
+ <member name="M:NetSharp.Sockets.SocketConnectionBase.Dispose">
<inheritdoc />
</member>
- <member name="M:NetSharp.Sockets.SocketConnection.Shutdown(System.Net.Sockets.SocketShutdown)">
+ <member name="M:NetSharp.Sockets.SocketConnectionBase.Shutdown(System.Net.Sockets.SocketShutdown)">
<summary>
Shuts down the underlying socket.
</summary>
@@ -631,78 +739,6 @@
Which socket transmission functions should be shut down on the socket.
</param>
</member>
- <member name="T:NetSharp.Sockets.SocketServerPacketHandler">
- <summary>
- Represents a method for serving request packets. This method should not throw any errors.
- </summary>
- <param name="requestPacket">
- The request packet received by the server.
- </param>
- <param name="clientEndPoint">
- The client from which the packet was received.
- </param>
- <returns>
- The response packet which should be sent out to the client. If no packet should be sent out, this method must return <see cref="F:NetSharp.Packets.NetworkPacket.NullPacket" />.
- </returns>
- </member>
- <member name="T:NetSharp.Sockets.SocketServer">
- <summary>
- Abstract base class for servers.
- </summary>
- </member>
- <member name="F:NetSharp.Sockets.SocketServer.PacketHandler">
- <summary>
- The packet handler delegate to use to respond to incoming requests.
- </summary>
- </member>
- <member name="M:NetSharp.Sockets.SocketServer.#ctor(System.Net.Sockets.AddressFamily@,System.Net.Sockets.SocketType@,System.Net.Sockets.ProtocolType@,NetSharp.Sockets.SocketServerPacketHandler@,System.Int32@,System.UInt16@)">
- <summary>
- Constructs a new instance of the <see cref="T:NetSharp.Sockets.SocketServer" /> class.
- </summary>
- <param name="connectionAddressFamily">
- The address family that the underlying connection should use.
- </param>
- <param name="connectionSocketType">
- The socket type that the underlying connection should use.
- </param>
- <param name="connectionProtocolType">
- The protocol type that the underlying connection should use.
- </param>
- <param name="packetHandler">
- The packet handler delegate to use to respond to incoming requests.
- </param>
- <param name="pooledBufferMaxSize">
- The maximum size in bytes of buffers held in the buffer pool.
- </param>
- <param name="preallocatedTransmissionArgs">
- The number of transmission args to preallocate.
- </param>
- </member>
- <member name="M:NetSharp.Sockets.SocketServer.DefaultPacketHandler(NetSharp.Packets.NetworkPacket@,System.Net.EndPoint@)">
- <summary>
- The default request packet handler for servers. Simply echoes back any received packets.
- </summary>
- <param name="request">
- The request packet that was received.
- </param>
- <param name="remoteEndPoint">
- The client from which the packet was received.
- </param>
- <returns>
- The received packet.
- </returns>
- </member>
- <member name="M:NetSharp.Sockets.SocketServer.RunAsync(System.Threading.CancellationToken)">
- <summary>
- Runs the server, handling requests from clients, until the <paramref name="cancellationToken" /> has its cancellation requested.
- </summary>
- <param name="cancellationToken">
- The <see cref="T:System.Threading.CancellationToken" /> upon whose cancellation the server should shut down.
- </param>
- <returns>
- A <see cref="T:System.Threading.Tasks.Task" /> representing the server's execution.
- </returns>
- </member>
<member name="T:NetSharp.Sockets.Stream.StreamSocketClientOptions">
<summary>
Provides additional configuration options for a <see cref="T:NetSharp.Sockets.Stream.StreamSocketClient" /> instance.
@@ -716,7 +752,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.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.
+ <see cref="M:NetSharp.Sockets.Stream.StreamSocketClient.SendAsync(System.Net.EndPoint@,System.ReadOnlyMemory{System.Byte},System.Net.Sockets.SocketFlags)" /> and <see cref="M:NetSharp.Sockets.Stream.StreamSocketClient.ReceiveAsync(System.Net.EndPoint@,System.Memory{System.Byte},System.Net.Sockets.SocketFlags)" /> methods.
</summary>
</member>
<member name="M:NetSharp.Sockets.Stream.StreamSocketClientOptions.#ctor(System.UInt16)">
@@ -739,19 +775,19 @@
<member name="M:NetSharp.Sockets.Stream.StreamSocketClient.HandleIoCompleted(System.Object,System.Net.Sockets.SocketAsyncEventArgs)">
<inheritdoc />
</member>
- <member name="M:NetSharp.Sockets.Stream.StreamSocketClient.ResetTransmissionArgs(System.Net.Sockets.SocketAsyncEventArgs)">
+ <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)">
+ <member name="M:NetSharp.Sockets.Stream.StreamSocketClient.ReceiveAsync(System.Net.EndPoint@,System.Memory{System.Byte},System.Net.Sockets.SocketFlags)">
<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)">
+ <member name="M:NetSharp.Sockets.Stream.StreamSocketClient.SendAsync(System.Net.EndPoint@,System.ReadOnlyMemory{System.Byte},System.Net.Sockets.SocketFlags)">
<inheritdoc />
</member>
<member name="T:NetSharp.Sockets.Stream.StreamSocketServerOptions">
@@ -787,7 +823,7 @@
The number of <see cref="T:System.Net.Sockets.SocketAsyncEventArgs" /> instances to preallocate.
</param>
</member>
- <member name="M:NetSharp.Sockets.Stream.StreamSocketServer.#ctor(System.Net.Sockets.AddressFamily@,System.Net.Sockets.ProtocolType@,NetSharp.Sockets.SocketServerPacketHandler@,System.Nullable{NetSharp.Sockets.Stream.StreamSocketServerOptions}@)">
+ <member name="M:NetSharp.Sockets.Stream.StreamSocketServer.#ctor(System.Net.Sockets.Socket@,NetSharp.Sockets.RawRequestPacketHandler@,System.Nullable{NetSharp.Sockets.Stream.StreamSocketServerOptions}@)">
<summary>
Constructs a new instance of the <see cref="T:NetSharp.Sockets.Stream.StreamSocketServer" /> class.
</summary>
@@ -808,7 +844,7 @@
<member name="M:NetSharp.Sockets.Stream.StreamSocketServer.HandleIoCompleted(System.Object,System.Net.Sockets.SocketAsyncEventArgs)">
<inheritdoc />
</member>
- <member name="M:NetSharp.Sockets.Stream.StreamSocketServer.ResetTransmissionArgs(System.Net.Sockets.SocketAsyncEventArgs)">
+ <member name="M:NetSharp.Sockets.Stream.StreamSocketServer.ResetTransmissionArgs(System.Net.Sockets.SocketAsyncEventArgs@)">
<inheritdoc />
</member>
<member name="M:NetSharp.Sockets.Stream.StreamSocketServer.RunAsync(System.Threading.CancellationToken)">
diff --git a/NetSharp/NetSharp/NetworkConnectionBase.cs b/NetSharp/NetSharp/NetworkConnectionBase.cs
@@ -0,0 +1,75 @@
+using NetSharp.Utils;
+
+using System;
+using System.Buffers;
+using System.Net;
+using System.Net.Sockets;
+
+namespace NetSharp
+{
+ public abstract class NetworkConnectionBase<TState> : IDisposable where TState : class
+ {
+ private readonly ArrayPool<byte> bufferPool;
+ protected readonly SlimObjectPool<TState> StateObjectPool;
+ protected readonly int BufferSize;
+ protected readonly Socket Connection;
+
+ protected NetworkConnectionBase(ref Socket rawConnection, int maxPooledBufferSize, int preallocatedStateObjects = 0)
+ {
+ Connection = rawConnection;
+
+ BufferSize = maxPooledBufferSize;
+ bufferPool = ArrayPool<byte>.Create(maxPooledBufferSize, 1_000);
+
+ StateObjectPool =
+ new SlimObjectPool<TState>(CreateStateObject, ResetStateObject, DestroyStateObject, CanReuseStateObject);
+ }
+
+ protected abstract bool CanReuseStateObject(in TState instance);
+
+ protected abstract TState CreateStateObject();
+
+ protected abstract void DestroyStateObject(TState instance);
+
+ /// <summary>
+ /// Allows for inheritors to dispose of their own resources.
+ /// </summary>
+ protected virtual void Dispose(bool disposing)
+ {
+ if (!disposing) return;
+
+ StateObjectPool.Dispose();
+ }
+
+ protected RentedBufferHandle RentBuffer(int desiredBufferSize)
+ {
+ byte[] rentedBuffer = bufferPool.Rent(desiredBufferSize);
+
+ return new RentedBufferHandle(ref rentedBuffer);
+ }
+
+ protected abstract void ResetStateObject(ref TState instance);
+
+ protected void ReturnBuffer(RentedBufferHandle handle)
+ {
+ bufferPool.Return(handle.RentedBuffer, true);
+ }
+
+ /// <inheritdoc />
+ public void Dispose()
+ {
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+
+ protected readonly struct RentedBufferHandle
+ {
+ public readonly byte[] RentedBuffer;
+
+ internal RentedBufferHandle(ref byte[] rentedBuffer)
+ {
+ RentedBuffer = rentedBuffer;
+ }
+ }
+ }
+}
+\ No newline at end of file
diff --git a/NetSharp/NetSharp/NetworkReaderBase.cs b/NetSharp/NetSharp/NetworkReaderBase.cs
@@ -0,0 +1,58 @@
+using System;
+using System.Net;
+using System.Net.Sockets;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace NetSharp
+{
+ public delegate bool NetworkRequestHandler(in EndPoint remoteEndPoint, ReadOnlyMemory<byte> requestBuffer,
+ Memory<byte> responseBuffer);
+
+ public abstract class NetworkReaderBase<TState> : NetworkConnectionBase<TState> where TState : class
+ {
+ private readonly CancellationTokenSource shutdownTokenSource;
+
+ protected readonly CancellationToken ShutdownToken;
+
+ protected readonly NetworkRequestHandler RequestHandler;
+
+ protected readonly EndPoint DefaultEndPoint;
+
+ /// <inheritdoc />
+ protected NetworkReaderBase(ref Socket rawConnection, NetworkRequestHandler? requestHandler, EndPoint defaultEndPoint, int maxPooledBufferSize, int preallocatedStateObjects = 0)
+ : base(ref rawConnection, maxPooledBufferSize, preallocatedStateObjects)
+ {
+ shutdownTokenSource = new CancellationTokenSource();
+ ShutdownToken = shutdownTokenSource.Token;
+
+ DefaultEndPoint = defaultEndPoint;
+
+ RequestHandler = requestHandler ?? DefaultRequestHandler;
+ }
+
+ public static bool DefaultRequestHandler(in EndPoint remoteEndPoint, ReadOnlyMemory<byte> requestBuffer,
+ Memory<byte> responseBuffer)
+ {
+ return requestBuffer.TryCopyTo(responseBuffer);
+ }
+
+ /// <inheritdoc />
+ protected override void Dispose(bool disposing)
+ {
+ if (!disposing) return;
+
+ shutdownTokenSource.Cancel();
+ shutdownTokenSource.Dispose();
+
+ base.Dispose(disposing);
+ }
+
+ public abstract void Start(ushort concurrentReadTasks);
+
+ public void Stop()
+ {
+ shutdownTokenSource.Cancel();
+ }
+ }
+}
+\ No newline at end of file
diff --git a/NetSharp/NetSharp/NetworkWriterBase.cs b/NetSharp/NetSharp/NetworkWriterBase.cs
@@ -0,0 +1,22 @@
+using System;
+using System.Net;
+using System.Net.Sockets;
+using System.Threading.Tasks;
+
+namespace NetSharp
+{
+ public abstract class NetworkWriterBase<TState> : NetworkConnectionBase<TState> where TState : class
+ {
+ /// <inheritdoc />
+ protected NetworkWriterBase(ref Socket rawConnection, int maxPooledBufferSize, int preallocatedStateObjects = 0)
+ : base(ref rawConnection, maxPooledBufferSize, preallocatedStateObjects)
+ {
+ }
+
+ public abstract int Write(EndPoint remoteEndPoint, ReadOnlyMemory<byte> writeBuffer,
+ SocketFlags flags = SocketFlags.None);
+
+ public abstract ValueTask<int> WriteAsync(EndPoint remoteEndPoint, ReadOnlyMemory<byte> writeBuffer,
+ SocketFlags flags = SocketFlags.None);
+ }
+}
+\ No newline at end of file
diff --git a/NetSharp/NetSharp/Sockets/Datagram/DatagramSocketClient.cs b/NetSharp/NetSharp/Sockets/Datagram/DatagramSocketClient.cs
@@ -40,14 +40,20 @@ namespace NetSharp.Sockets.Datagram
//TODO address the need to handle series of network packets, not just single packets
//TODO document class
- public sealed class DatagramSocketClient : SocketClient
+ public sealed class DatagramSocketClient : RawSocketClient
{
private readonly DatagramSocketClientOptions clientOptions;
- public DatagramSocketClient(in AddressFamily connectionAddressFamily, in ProtocolType connectionProtocolType,
- in DatagramSocketClientOptions? clientOptions = null) : base(in connectionAddressFamily, SocketType.Dgram, in connectionProtocolType,
- NetworkPacket.TotalSize, clientOptions?.PreallocatedTransmissionArgs ?? DatagramSocketClientOptions.Defaults.PreallocatedTransmissionArgs)
+ public DatagramSocketClient(ref Socket rawConnection, in DatagramSocketClientOptions? clientOptions = null)
+ : base(ref rawConnection,
+ NetworkPacket.TotalSize,
+ clientOptions?.PreallocatedTransmissionArgs ?? DatagramSocketClientOptions.Defaults.PreallocatedTransmissionArgs)
{
+ if (rawConnection.SocketType != SocketType.Dgram)
+ {
+ throw new ArgumentException($"Only {SocketType.Dgram} is supported!", nameof(rawConnection));
+ }
+
this.clientOptions = clientOptions ?? DatagramSocketClientOptions.Defaults;
}
@@ -78,7 +84,7 @@ namespace NetSharp.Sockets.Datagram
break;
}
- TransmissionArgsPool.Return(args);
+ ArgsPool.Return(args);
}
private void CompleteReceiveFrom(SocketAsyncEventArgs args)
@@ -105,7 +111,7 @@ namespace NetSharp.Sockets.Datagram
break;
}
- TransmissionArgsPool.Return(args);
+ ArgsPool.Return(args);
}
private void CompleteSendTo(SocketAsyncEventArgs args)
@@ -133,7 +139,7 @@ namespace NetSharp.Sockets.Datagram
}
BufferPool.Return(sendToken.RentedBuffer, true);
- TransmissionArgsPool.Return(args);
+ ArgsPool.Return(args);
}
/// <inheritdoc />
@@ -186,7 +192,7 @@ namespace NetSharp.Sockets.Datagram
}
/// <inheritdoc />
- protected override void ResetTransmissionArgs(SocketAsyncEventArgs args)
+ protected override void ResetTransmissionArgs(ref SocketAsyncEventArgs args)
{
}
@@ -200,45 +206,23 @@ namespace NetSharp.Sockets.Datagram
}
/// <inheritdoc />
- public override ValueTask<TransmissionResult> ReceiveAsync(in EndPoint remoteEndPoint, Memory<byte> receiveBuffer, SocketFlags flags = SocketFlags.None,
- CancellationToken cancellationToken = default)
+ public override ValueTask<TransmissionResult> ReceiveAsync(in EndPoint remoteEndPoint, Memory<byte> receiveBuffer, SocketFlags flags = SocketFlags.None)
{
TaskCompletionSource<TransmissionResult> tcs = new TaskCompletionSource<TransmissionResult>();
- SocketAsyncEventArgs args = TransmissionArgsPool.Rent();
+ SocketAsyncEventArgs args = ArgsPool.Rent();
args.SetBuffer(receiveBuffer);
args.RemoteEndPoint = remoteEndPoint;
args.SocketFlags = flags;
- args.UserToken = new AsyncReceiveToken(in tcs, in cancellationToken);
+ args.UserToken = new AsyncReceiveToken(in tcs, CancellationToken.None);
- if (cancellationToken == default)
- {
- if (Connection.ReceiveFromAsync(args)) return new ValueTask<TransmissionResult>(tcs.Task);
- }
- else
- {
- // TODO find out why the fricc we leak memory
- CancellationTokenRegistration cancellationRegistration =
- cancellationToken.Register(CancelAsyncReceiveCallback, args);
-
- if (Connection.ReceiveFromAsync(args))
- return new ValueTask<TransmissionResult>(
- tcs.Task.ContinueWith((task, state) =>
- {
- ((CancellationTokenRegistration)state).Dispose();
-
- return task.Result;
- }, cancellationRegistration, CancellationToken.None)
- );
-
- cancellationRegistration.Dispose();
- }
+ if (Connection.ReceiveFromAsync(args)) return new ValueTask<TransmissionResult>(tcs.Task);
TransmissionResult result = new TransmissionResult(in args);
- TransmissionArgsPool.Return(args);
+ ArgsPool.Return(args);
return new ValueTask<TransmissionResult>(result);
}
@@ -252,12 +236,11 @@ namespace NetSharp.Sockets.Datagram
}
/// <inheritdoc />
- public override ValueTask<TransmissionResult> SendAsync(in EndPoint remoteEndPoint, ReadOnlyMemory<byte> sendBuffer, SocketFlags flags = SocketFlags.None,
- CancellationToken cancellationToken = default)
+ public override ValueTask<TransmissionResult> SendAsync(in EndPoint remoteEndPoint, ReadOnlyMemory<byte> sendBuffer, SocketFlags flags = SocketFlags.None)
{
TaskCompletionSource<TransmissionResult> tcs = new TaskCompletionSource<TransmissionResult>();
- SocketAsyncEventArgs args = TransmissionArgsPool.Rent();
+ SocketAsyncEventArgs args = ArgsPool.Rent();
byte[] transmissionBuffer = BufferPool.Rent(sendBuffer.Length);
sendBuffer.CopyTo(transmissionBuffer);
@@ -266,35 +249,14 @@ namespace NetSharp.Sockets.Datagram
args.RemoteEndPoint = remoteEndPoint;
args.SocketFlags = flags;
- args.UserToken = new AsyncSendToken(in tcs, in transmissionBuffer, in cancellationToken);
-
- if (cancellationToken == default)
- {
- if (Connection.SendToAsync(args)) return new ValueTask<TransmissionResult>(tcs.Task);
- }
- else
- {
- // TODO find out why the fricc we leak memory
- CancellationTokenRegistration cancellationRegistration =
- cancellationToken.Register(CancelAsyncSendCallback, args);
-
- if (Connection.SendToAsync(args))
- return new ValueTask<TransmissionResult>(
- tcs.Task.ContinueWith((task, state) =>
- {
- ((CancellationTokenRegistration)state).Dispose();
+ args.UserToken = new AsyncSendToken(in tcs, ref transmissionBuffer, CancellationToken.None);
- return task.Result;
- }, cancellationRegistration, CancellationToken.None)
- );
-
- cancellationRegistration.Dispose();
- }
+ if (Connection.SendToAsync(args)) return new ValueTask<TransmissionResult>(tcs.Task);
TransmissionResult result = new TransmissionResult(in args);
BufferPool.Return(transmissionBuffer, true);
- TransmissionArgsPool.Return(args);
+ ArgsPool.Return(args);
return new ValueTask<TransmissionResult>(result);
}
diff --git a/NetSharp/NetSharp/Sockets/Datagram/DatagramSocketServer.cs b/NetSharp/NetSharp/Sockets/Datagram/DatagramSocketServer.cs
@@ -50,7 +50,7 @@ namespace NetSharp.Sockets.Datagram
//TODO address the need to handle series of network packets, not just single packets
//TODO document class
- public sealed class DatagramSocketServer : SocketServer
+ public sealed class DatagramSocketServer : RawSocketServer
{
private static readonly EndPoint AnyRemoteEndPoint = new IPEndPoint(IPAddress.Any, 0);
@@ -65,11 +65,17 @@ namespace NetSharp.Sockets.Datagram
/// Additional options to configure the server.
/// </param>
/// <inheritdoc />
- public DatagramSocketServer(in AddressFamily connectionAddressFamily, in ProtocolType connectionProtocolType,
- in SocketServerPacketHandler packetHandler, in DatagramSocketServerOptions? serverOptions = null)
- : base(in connectionAddressFamily, SocketType.Dgram, in connectionProtocolType, in packetHandler,
- NetworkPacket.TotalSize, serverOptions?.PreallocatedTransmissionArgs ?? DatagramSocketServerOptions.Defaults.PreallocatedTransmissionArgs)
+ public DatagramSocketServer(ref Socket rawConnection, in RawRequestPacketHandler packetHandler, in DatagramSocketServerOptions? serverOptions = null)
+ : base(ref rawConnection,
+ NetworkPacket.TotalSize,
+ serverOptions?.PreallocatedTransmissionArgs ?? DatagramSocketServerOptions.Defaults.PreallocatedTransmissionArgs,
+ packetHandler)
{
+ if (rawConnection.SocketType != SocketType.Dgram)
+ {
+ throw new ArgumentException($"Only {SocketType.Dgram} is supported!", nameof(rawConnection));
+ }
+
this.serverOptions = serverOptions ?? DatagramSocketServerOptions.Defaults;
}
@@ -84,30 +90,35 @@ namespace NetSharp.Sockets.Datagram
if (receiveArgs.SocketError == SocketError.Success)
{
- NetworkPacket.Deserialise(receiveArgs.MemoryBuffer, out NetworkPacket request);
+ byte[] responseBuffer = BufferPool.Rent(MaxBufferSize);
- NetworkPacket response = PacketHandler(in request, receiveArgs.RemoteEndPoint);
+ bool responseExists = PacketHandler(receiveArgs.RemoteEndPoint, receiveToken.RentedBuffer, responseBuffer);
+ BufferPool.Return(receiveToken.RentedBuffer, true);
- if (!response.Equals(NetworkPacket.NullPacket))
- {
- byte[] sendBuffer = BufferPool.Rent(NetworkPacket.TotalSize);
- Memory<byte> sendBufferMemory = new Memory<byte>(sendBuffer);
+ //NetworkPacket.Deserialise(receiveArgs.MemoryBuffer, out NetworkPacket request);
+ //NetworkPacket response = PacketHandler(in request, receiveArgs.RemoteEndPoint);
- NetworkPacket.Serialise(response, sendBufferMemory);
+ if (responseExists)
+ {
+ //byte[] sendBuffer = BufferPool.Rent(NetworkPacket.TotalSize);
+ //Memory<byte> sendBufferMemory = new Memory<byte>(sendBuffer);
+ //NetworkPacket.Serialise(response, sendBufferMemory);
- receiveArgs.SetBuffer(sendBufferMemory);
- receiveArgs.UserToken = new SocketOperationToken(in sendBuffer);
+ receiveArgs.SetBuffer(responseBuffer);
+ receiveArgs.UserToken = new SocketOperationToken(ref responseBuffer);
SendTo(receiveArgs);
}
-
- BufferPool.Return(receiveToken.RentedBuffer, true);
+ else
+ {
+ BufferPool.Return(responseBuffer, true);
+ }
}
else
{
BufferPool.Return(receiveToken.RentedBuffer, true);
- TransmissionArgsPool.Return(receiveArgs);
+ ArgsPool.Return(receiveArgs);
}
}
@@ -117,14 +128,14 @@ namespace NetSharp.Sockets.Datagram
BufferPool.Return(sendToken.RentedBuffer, true);
- TransmissionArgsPool.Return(sendArgs);
+ ArgsPool.Return(sendArgs);
}
private void ReceiveFrom(SocketAsyncEventArgs receiveArgs)
{
if (serverShutdownToken.IsCancellationRequested)
{
- TransmissionArgsPool.Return(receiveArgs);
+ ArgsPool.Return(receiveArgs);
return;
}
@@ -133,13 +144,13 @@ namespace NetSharp.Sockets.Datagram
Memory<byte> receiveBufferMemory = new Memory<byte>(receiveBuffer);
receiveArgs.SetBuffer(receiveBufferMemory);
- receiveArgs.UserToken = new SocketOperationToken(in receiveBuffer);
+ receiveArgs.UserToken = new SocketOperationToken(ref receiveBuffer);
bool operationPending = Connection.ReceiveFromAsync(receiveArgs);
if (operationPending) return;
- SocketAsyncEventArgs newReceiveArgs = TransmissionArgsPool.Rent();
+ SocketAsyncEventArgs newReceiveArgs = ArgsPool.Rent();
newReceiveArgs.RemoteEndPoint = AnyRemoteEndPoint;
ReceiveFrom(newReceiveArgs); // start a new receive from operation immediately, to not drop any packets
@@ -155,7 +166,7 @@ namespace NetSharp.Sockets.Datagram
BufferPool.Return(sendToken.RentedBuffer, true);
- TransmissionArgsPool.Return(sendArgs);
+ ArgsPool.Return(sendArgs);
return;
}
@@ -198,7 +209,7 @@ namespace NetSharp.Sockets.Datagram
switch (args.LastOperation)
{
case SocketAsyncOperation.ReceiveFrom:
- SocketAsyncEventArgs newReceiveArgs = TransmissionArgsPool.Rent();
+ SocketAsyncEventArgs newReceiveArgs = ArgsPool.Rent();
newReceiveArgs.RemoteEndPoint = AnyRemoteEndPoint;
ReceiveFrom(newReceiveArgs); // start a new receive from operation immediately, to not drop any packets
@@ -218,7 +229,7 @@ namespace NetSharp.Sockets.Datagram
}
/// <inheritdoc />
- protected override void ResetTransmissionArgs(SocketAsyncEventArgs args)
+ protected override void ResetTransmissionArgs(ref SocketAsyncEventArgs args)
{
}
@@ -229,7 +240,7 @@ namespace NetSharp.Sockets.Datagram
for (int i = 0; i < serverOptions.ConcurrentReceiveFromCalls; i++)
{
- SocketAsyncEventArgs newReceiveArgs = TransmissionArgsPool.Rent();
+ SocketAsyncEventArgs newReceiveArgs = ArgsPool.Rent();
newReceiveArgs.RemoteEndPoint = AnyRemoteEndPoint;
ReceiveFrom(newReceiveArgs);
@@ -244,7 +255,7 @@ namespace NetSharp.Sockets.Datagram
{
public readonly byte[] RentedBuffer;
- public SocketOperationToken(in byte[] rentedBuffer)
+ public SocketOperationToken(ref byte[] rentedBuffer)
{
RentedBuffer = rentedBuffer;
}
diff --git a/NetSharp/NetSharp/Sockets/RawSocketClient.cs b/NetSharp/NetSharp/Sockets/RawSocketClient.cs
@@ -0,0 +1,307 @@
+using NetSharp.Utils;
+
+using System;
+using System.Net;
+using System.Net.Sockets;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace NetSharp.Sockets
+{
+ /// <summary>
+ /// Abstract base class for clients.
+ /// </summary>
+ /// TODO implement proper memory leak-free cancellation of network IO operations
+ public abstract class RawSocketClient : SocketConnectionBase
+ {
+ /// <summary>
+ /// Constructs a new instance of the <see cref="RawSocketClient" /> class.
+ /// </summary>
+ /// <param name="rawConnection">
+ /// The underlying <see cref="Socket"/> object which should be wrapped by this instance.
+ /// </param>
+ /// <param name="pooledBufferMaxSize">
+ /// The maximum size in bytes of buffers held in the buffer pool.
+ /// </param>
+ /// <param name="preallocatedTransmissionArgs">
+ /// The number of transmission args to preallocate.
+ /// </param>
+ protected RawSocketClient(ref Socket rawConnection, int pooledBufferMaxSize, ushort preallocatedTransmissionArgs)
+ : base(ref rawConnection, pooledBufferMaxSize, preallocatedTransmissionArgs)
+ {
+ }
+
+ /// <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;
+
+ AsyncOperationToken token = (AsyncOperationToken)args.UserToken;
+
+ token.CompletionSource.SetResult(false);
+
+ 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;
+
+ AsyncReceiveToken token = (AsyncReceiveToken)args.UserToken;
+
+ token.CompletionSource.SetResult(TransmissionResult.Timeout);
+
+ 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;
+
+ AsyncSendToken token = (AsyncSendToken)args.UserToken;
+
+ token.CompletionSource.SetResult(TransmissionResult.Timeout);
+
+ BufferPool.Return(token.RentedBuffer, true);
+ DestroyTransmissionArgs(args);
+ }
+
+ /// <summary>
+ /// Connects the client to the specified end point. If called on a <see cref="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" />).
+ /// </summary>
+ /// <param name="remoteEndPoint">
+ /// The remote end point which to which to connect the client.
+ /// </param>
+ public void Connect(in EndPoint remoteEndPoint)
+ {
+ Connection.Connect(remoteEndPoint);
+ }
+
+ /// <summary>
+ /// Asynchronously connects the client to the specified end point. If called on a <see cref="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" />).
+ /// </summary>
+ /// <param name="remoteEndPoint">
+ /// The remote end point which to which to connect the client.
+ /// </param>
+ /// <returns>
+ /// A <see cref="ValueTask" /> representing the connection attempt.
+ /// </returns>
+ public ValueTask ConnectAsync(in EndPoint remoteEndPoint)
+ {
+ TaskCompletionSource<bool> tcs = new TaskCompletionSource<bool>();
+
+ SocketAsyncEventArgs args = ArgsPool.Rent();
+
+ args.RemoteEndPoint = remoteEndPoint;
+ args.UserToken = new AsyncOperationToken(in tcs, CancellationToken.None);
+
+ if (Connection.ConnectAsync(args)) return new ValueTask(tcs.Task);
+
+ ArgsPool.Return(args);
+
+ return new ValueTask();
+ }
+
+ /// <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>
+ /// <returns>
+ /// The result of the asynchronous receive operation.
+ /// </returns>
+ public abstract ValueTask<TransmissionResult> ReceiveAsync(in EndPoint remoteEndPoint, Memory<byte> receiveBuffer,
+ SocketFlags flags = SocketFlags.None);
+
+ /// <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>
+ /// <returns>
+ /// The result of the asynchronous send operation.
+ /// </returns>
+ public abstract ValueTask<TransmissionResult> SendAsync(in EndPoint remoteEndPoint, ReadOnlyMemory<byte> sendBuffer,
+ SocketFlags flags = SocketFlags.None);
+
+ /// <summary>
+ /// A state token for asynchronous socket operations.
+ /// </summary>
+ protected readonly struct AsyncOperationToken
+ {
+ /// <summary>
+ /// The <see cref="System.Threading.CancellationToken" /> associated with the socket operation.
+ /// </summary>
+ public readonly CancellationToken CancellationToken;
+
+ /// <summary>
+ /// The completion source which wraps the event-based APM, and provides an awaitable <see cref="Task" />.
+ /// </summary>
+ public readonly TaskCompletionSource<bool> CompletionSource;
+
+ /// <summary>
+ /// Constructs a new instance of the <see cref="AsyncOperationToken" /> struct.
+ /// </summary>
+ /// <param name="completionSource">
+ /// The completion source to trigger when the socket operation completes.
+ /// </param>
+ /// <param name="cancellationToken">
+ /// The cancellation token to observe during the operation.
+ /// </param>
+ public AsyncOperationToken(in TaskCompletionSource<bool> completionSource, in CancellationToken cancellationToken)
+ {
+ CompletionSource = completionSource;
+
+ CancellationToken = cancellationToken;
+ }
+ }
+
+ /// <summary>
+ /// A state token for asynchronous incoming network IO operations.
+ /// </summary>
+ protected readonly struct AsyncReceiveToken
+ {
+ /// <summary>
+ /// The <see cref="System.Threading.CancellationToken" /> associated with the network IO operation.
+ /// </summary>
+ public readonly CancellationToken CancellationToken;
+
+ /// <summary>
+ /// The completion source which wraps the event-based APM, and provides an awaitable <see cref="Task" />.
+ /// </summary>
+ public readonly TaskCompletionSource<TransmissionResult> CompletionSource;
+
+ /// <summary>
+ /// Constructs a new instance of the <see cref="AsyncReceiveToken" /> struct.
+ /// </summary>
+ /// <param name="completionSource">
+ /// The completion source to trigger when the IO operation completes.
+ /// </param>
+ /// <param name="cancellationToken">
+ /// The cancellation token to observe during the operation.
+ /// </param>
+ public AsyncReceiveToken(in TaskCompletionSource<TransmissionResult> completionSource, in CancellationToken cancellationToken)
+ {
+ CompletionSource = completionSource;
+
+ CancellationToken = cancellationToken;
+ }
+ }
+
+ /// <summary>
+ /// A state token for asynchronous outgoing network IO operations.
+ /// </summary>
+ protected readonly struct AsyncSendToken
+ {
+ /// <summary>
+ /// The <see cref="System.Threading.CancellationToken" /> associated with the network IO operation.
+ /// </summary>
+ public readonly CancellationToken CancellationToken;
+
+ /// <summary>
+ /// The completion source which wraps the event-based APM, and provides an awaitable <see cref="Task" />.
+ /// </summary>
+ public readonly TaskCompletionSource<TransmissionResult> CompletionSource;
+
+ /// <summary>
+ /// The rented buffer which holds the user's data.
+ /// </summary>
+ public readonly byte[] RentedBuffer;
+
+ /// <summary>
+ /// Constructs a new instance of the <see cref="AsyncSendToken" /> struct.
+ /// </summary>
+ /// <param name="completionSource">
+ /// The completion source to trigger when the IO operation completes.
+ /// </param>
+ /// <param name="bufferHandle">
+ /// The buffer holding the user's data.
+ /// </param>
+ /// <param name="cancellationToken">
+ /// The cancellation token to observe during the operation.
+ /// </param>
+ public AsyncSendToken(in TaskCompletionSource<TransmissionResult> completionSource, ref byte[] bufferHandle, in CancellationToken cancellationToken)
+ {
+ CompletionSource = completionSource;
+
+ RentedBuffer = bufferHandle;
+
+ CancellationToken = cancellationToken;
+ }
+ }
+ }
+}
+\ No newline at end of file
diff --git a/NetSharp/NetSharp/Sockets/RawSocketServer.cs b/NetSharp/NetSharp/Sockets/RawSocketServer.cs
@@ -0,0 +1,84 @@
+using System;
+using NetSharp.Packets;
+
+using System.Net;
+using System.Net.Sockets;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace NetSharp.Sockets
+{
+ /// <summary>
+ /// Represents a method for serving request packets. This method should not throw any errors.
+ /// </summary>
+ /// <param name="clientEndPoint">
+ /// The client from which the packet was received.
+ /// </param>
+ /// <param name="requestBuffer">
+ /// The buffer holding the data received from the client.
+ /// </param>
+ /// <param name="responseBuffer">
+ /// The buffer into which the optional response should be written.
+ /// </param>
+ /// <returns>
+ /// Whether a response was generated which should be sent back to the client.
+ /// </returns>
+ public delegate bool RawRequestPacketHandler(in EndPoint clientEndPoint, ReadOnlyMemory<byte> requestBuffer, Memory<byte> responseBuffer);
+
+ /// <summary>
+ /// Abstract base class for servers.
+ /// </summary>
+ public abstract class RawSocketServer : SocketConnectionBase
+ {
+ /// <summary>
+ /// The packet handler delegate to use to respond to incoming requests.
+ /// </summary>
+ protected readonly RawRequestPacketHandler PacketHandler;
+
+ /// <summary>
+ /// Constructs a new instance of the <see cref="RawSocketServer" /> class.
+ /// </summary>
+ /// <param name="rawConnection">
+ /// The underlying <see cref="Socket"/> object which should be wrapped by this instance.
+ /// </param>
+ /// <param name="packetHandler">
+ /// The packet handler delegate to use to respond to incoming requests.
+ /// </param>
+ /// <param name="pooledBufferMaxSize">
+ /// The maximum size in bytes of buffers held in the buffer pool.
+ /// </param>
+ /// <param name="preallocatedTransmissionArgs">
+ /// The number of transmission args to preallocate.
+ /// </param>
+ protected RawSocketServer(ref Socket rawConnection, int pooledBufferMaxSize, ushort preallocatedTransmissionArgs, RawRequestPacketHandler? packetHandler)
+ : base(ref rawConnection, pooledBufferMaxSize, preallocatedTransmissionArgs)
+ {
+ PacketHandler = packetHandler ?? DefaultRawPacketHandler;
+ }
+
+ /// <summary>
+ /// The default request handler for servers. Simply echoes back any received data.
+ /// </summary>
+ /// <param name="remoteEndPoint">
+ /// The client from which the packet was received.
+ /// </param>
+ /// <param name="requestBuffer">The data that was received.</param>
+ /// <param name="responseBuffer">The data that should be sent back.</param>
+ /// <returns>
+ /// Whether to send back a response.
+ /// </returns>
+ public static bool DefaultRawPacketHandler(in EndPoint remoteEndPoint, ReadOnlyMemory<byte> requestBuffer,
+ Memory<byte> responseBuffer) => requestBuffer.TryCopyTo(responseBuffer);
+
+ /// <summary>
+ /// Runs the server, handling requests from clients, until the <paramref name="cancellationToken" /> has its cancellation requested.
+ /// </summary>
+ /// <param name="cancellationToken">
+ /// The <see cref="CancellationToken" /> upon whose cancellation the server should shut down.
+ /// </param>
+ /// <returns>
+ /// A <see cref="Task" /> representing the server's execution.
+ /// </returns>
+ public abstract Task RunAsync(CancellationToken cancellationToken = default);
+ }
+}
+\ No newline at end of file
diff --git a/NetSharp/NetSharp/Sockets/SocketClient.cs b/NetSharp/NetSharp/Sockets/SocketClient.cs
@@ -1,344 +0,0 @@
-using NetSharp.Utils;
-
-using System;
-using System.Net;
-using System.Net.Sockets;
-using System.Threading;
-using System.Threading.Tasks;
-
-namespace NetSharp.Sockets
-{
- /// <summary>
- /// Abstract base class for clients.
- /// </summary>
- /// TODO implement proper memory leak-free cancellation of network IO operations
- public abstract class SocketClient : SocketConnection
- {
- /// <summary>
- /// Constructs a new instance of the <see cref="SocketClient" /> class.
- /// </summary>
- /// <param name="connectionAddressFamily">
- /// The address family that the underlying connection should use.
- /// </param>
- /// <param name="connectionSocketType">
- /// The socket type that the underlying connection should use.
- /// </param>
- /// <param name="connectionProtocolType">
- /// The protocol type that the underlying connection should use.
- /// </param>
- /// <param name="pooledBufferMaxSize">
- /// The maximum size in bytes of buffers held in the buffer pool.
- /// </param>
- /// <param name="preallocatedTransmissionArgs">
- /// The number of transmission args to preallocate.
- /// </param>
- protected SocketClient(in AddressFamily connectionAddressFamily, in SocketType connectionSocketType, in ProtocolType connectionProtocolType,
- in int pooledBufferMaxSize, in ushort preallocatedTransmissionArgs) : base(in connectionAddressFamily, in connectionSocketType,
- in connectionProtocolType, pooledBufferMaxSize, preallocatedTransmissionArgs)
- {
- }
-
- /// <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;
-
- AsyncOperationToken token = (AsyncOperationToken)args.UserToken;
-
- token.CompletionSource.SetResult(false);
-
- 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;
-
- AsyncReceiveToken token = (AsyncReceiveToken)args.UserToken;
-
- token.CompletionSource.SetResult(TransmissionResult.Timeout);
-
- 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;
-
- AsyncSendToken token = (AsyncSendToken)args.UserToken;
-
- token.CompletionSource.SetResult(TransmissionResult.Timeout);
-
- BufferPool.Return(token.RentedBuffer, true);
- DestroyTransmissionArgs(args);
- }
-
- /// <summary>
- /// Connects the client to the specified end point. If called on a <see cref="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" />).
- /// </summary>
- /// <param name="remoteEndPoint">
- /// The remote end point which to which to connect the client.
- /// </param>
- public void Connect(in EndPoint remoteEndPoint)
- {
- Connection.Connect(remoteEndPoint);
- }
-
- /// <summary>
- /// Asynchronously connects the client to the specified end point. If called on a <see cref="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" />).
- /// </summary>
- /// <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>
- public ValueTask ConnectAsync(in EndPoint remoteEndPoint, CancellationToken cancellationToken = default)
- {
- TaskCompletionSource<bool> tcs = new TaskCompletionSource<bool>();
-
- SocketAsyncEventArgs args = TransmissionArgsPool.Rent();
-
- args.RemoteEndPoint = remoteEndPoint;
- args.UserToken = new AsyncOperationToken(in tcs, in cancellationToken);
-
- 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();
-
- return task.Result;
- }, cancellationRegistration, CancellationToken.None)
- );
-
- cancellationRegistration.Dispose();
- }
-
- TransmissionArgsPool.Return(args);
-
- return new ValueTask();
- }
-
- /// <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
- {
- /// <summary>
- /// The <see cref="System.Threading.CancellationToken" /> associated with the socket operation.
- /// </summary>
- public readonly CancellationToken CancellationToken;
-
- /// <summary>
- /// The completion source which wraps the event-based APM, and provides an awaitable <see cref="Task" />.
- /// </summary>
- public readonly TaskCompletionSource<bool> CompletionSource;
-
- /// <summary>
- /// Constructs a new instance of the <see cref="AsyncOperationToken" /> struct.
- /// </summary>
- /// <param name="completionSource">
- /// The completion source to trigger when the socket operation completes.
- /// </param>
- /// <param name="cancellationToken">
- /// The cancellation token to observe during the operation.
- /// </param>
- public AsyncOperationToken(in TaskCompletionSource<bool> completionSource, in CancellationToken cancellationToken)
- {
- CompletionSource = completionSource;
-
- CancellationToken = cancellationToken;
- }
- }
-
- /// <summary>
- /// A state token for asynchronous incoming network IO operations.
- /// </summary>
- protected readonly struct AsyncReceiveToken
- {
- /// <summary>
- /// The <see cref="System.Threading.CancellationToken" /> associated with the network IO operation.
- /// </summary>
- public readonly CancellationToken CancellationToken;
-
- /// <summary>
- /// The completion source which wraps the event-based APM, and provides an awaitable <see cref="Task" />.
- /// </summary>
- public readonly TaskCompletionSource<TransmissionResult> CompletionSource;
-
- /// <summary>
- /// Constructs a new instance of the <see cref="AsyncReceiveToken" /> struct.
- /// </summary>
- /// <param name="completionSource">
- /// The completion source to trigger when the IO operation completes.
- /// </param>
- /// <param name="cancellationToken">
- /// The cancellation token to observe during the operation.
- /// </param>
- public AsyncReceiveToken(in TaskCompletionSource<TransmissionResult> completionSource, in CancellationToken cancellationToken)
- {
- CompletionSource = completionSource;
-
- CancellationToken = cancellationToken;
- }
- }
-
- /// <summary>
- /// A state token for asynchronous outgoing network IO operations.
- /// </summary>
- protected readonly struct AsyncSendToken
- {
- /// <summary>
- /// The <see cref="System.Threading.CancellationToken" /> associated with the network IO operation.
- /// </summary>
- public readonly CancellationToken CancellationToken;
-
- /// <summary>
- /// The completion source which wraps the event-based APM, and provides an awaitable <see cref="Task" />.
- /// </summary>
- public readonly TaskCompletionSource<TransmissionResult> CompletionSource;
-
- /// <summary>
- /// The rented buffer which holds the user's data.
- /// </summary>
- public readonly byte[] RentedBuffer;
-
- /// <summary>
- /// Constructs a new instance of the <see cref="AsyncSendToken" /> struct.
- /// </summary>
- /// <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>
- public AsyncSendToken(in TaskCompletionSource<TransmissionResult> completionSource, in byte[] rentedBuffer, in CancellationToken cancellationToken)
- {
- CompletionSource = completionSource;
-
- RentedBuffer = rentedBuffer;
-
- CancellationToken = cancellationToken;
- }
- }
- }
-}
-\ No newline at end of file
diff --git a/NetSharp/NetSharp/Sockets/SocketConnection.cs b/NetSharp/NetSharp/Sockets/SocketConnection.cs
@@ -1,177 +0,0 @@
-using NetSharp.Utils;
-
-using System;
-using System.Buffers;
-using System.Net;
-using System.Net.Sockets;
-
-namespace NetSharp.Sockets
-{
- /// <summary>
- /// Abstract base class for clients and servers.
- /// </summary>
- public abstract class SocketConnection : IDisposable
- {
- /// <summary>
- /// Pools arrays to function as temporary buffers during network read/write operations.
- /// </summary>
- protected readonly ArrayPool<byte> BufferPool;
-
- /// <summary>
- /// Pools <see cref="SocketAsyncEventArgs" /> objects for use during network read/write operations and calls to
- /// <see cref="Socket" />.XXXAsync( <see cref="SocketAsyncEventArgs" />) methods.
- /// </summary>
- protected readonly SlimObjectPool<SocketAsyncEventArgs> TransmissionArgsPool;
-
- /// <summary>
- /// The underlying <see cref="Socket" /> which provides access to network operations.
- /// </summary>
- protected Socket Connection;
-
- /// <summary>
- /// Constructs a new instance of the <see cref="SocketConnection" /> class.
- /// </summary>
- /// <param name="connectionAddressFamily">
- /// The address family for the underlying socket.
- /// </param>
- /// <param name="connectionSocketType">
- /// The socket type for the underlying socket.
- /// </param>
- /// <param name="connectionProtocolType">
- /// The protocol type for the underlying socket.
- /// </param>
- /// <param name="pooledBufferMaxSize">
- /// The maximum size in bytes of buffers held in the buffer pool.
- /// </param>
- /// <param name="preallocatedTransmissionArgs">
- /// The number of <see cref="SocketAsyncEventArgs" /> objects to initially preallocate.
- /// </param>
- private protected SocketConnection(in AddressFamily connectionAddressFamily, in SocketType connectionSocketType,
- in ProtocolType connectionProtocolType, in int pooledBufferMaxSize, in ushort preallocatedTransmissionArgs)
- {
- Connection = new Socket(connectionAddressFamily, connectionSocketType, connectionProtocolType);
-
- BufferPool = ArrayPool<byte>.Create(pooledBufferMaxSize, 1000);
-
- TransmissionArgsPool = new SlimObjectPool<SocketAsyncEventArgs>(CreateTransmissionArgs,
- ResetTransmissionArgs, DestroyTransmissionArgs, CanTransmissionArgsBeReused);
-
- // TODO refactor into a cleaner structure, with a better method of seeding the object pool
- for (ushort i = 0; i < preallocatedTransmissionArgs; i++)
- {
- SocketAsyncEventArgs args = CreateTransmissionArgs();
-
- TransmissionArgsPool.Return(args);
- }
- }
-
- /// <summary>
- /// The local endpoint to which the underlying <see cref="Socket" /> is bound.
- /// </summary>
- public EndPoint LocalEndPoint
- {
- get { return Connection.LocalEndPoint; }
- }
-
- /// <summary>
- /// Delegate method used to check whether the given used <see cref="SocketAsyncEventArgs" /> instance can be reused by the
- /// <see cref="TransmissionArgsPool" />. If this method returns <c>true</c>, <see cref="ResetTransmissionArgs" /> is called on the given
- /// <paramref name="args" />. Otherwise, <see cref="DestroyTransmissionArgs" /> is called.
- /// </summary>
- /// <param name="args">
- /// The <see cref="SocketAsyncEventArgs" /> instance to check.
- /// </param>
- /// <returns>
- /// Whether the given <paramref name="args" /> should be reset and reused, or should be destroyed.
- /// </returns>
- protected abstract bool CanTransmissionArgsBeReused(in SocketAsyncEventArgs args);
-
- /// <summary>
- /// Delegate method used to construct fresh <see cref="SocketAsyncEventArgs" /> instances for use in the <see cref="TransmissionArgsPool" />.
- /// The resulting instance should register <see cref="HandleIoCompleted" /> as an event handler for the
- /// <see cref="SocketAsyncEventArgs.Completed" /> event.
- /// </summary>
- /// <returns>
- /// The configured <see cref="SocketAsyncEventArgs" /> instance.
- /// </returns>
- protected abstract SocketAsyncEventArgs CreateTransmissionArgs();
-
- /// <summary>
- /// Delegate method to destroy used <see cref="SocketAsyncEventArgs" /> instances that cannot be reused by the
- /// <see cref="TransmissionArgsPool" />. This method should deregister <see cref="HandleIoCompleted" /> as an event handler for the
- /// <see cref="SocketAsyncEventArgs.Completed" /> event.
- /// </summary>
- /// <param name="remoteConnectionArgs">
- /// The <see cref="SocketAsyncEventArgs" /> which should be destroyed.
- /// </param>
- protected abstract void DestroyTransmissionArgs(SocketAsyncEventArgs remoteConnectionArgs);
-
- /// <summary>
- /// Disposes of managed and unmanaged resources used by the <see cref="SocketConnection" /> class.
- /// </summary>
- /// <param name="disposing">
- /// Whether this call was made by a call to <see cref="Dispose()" />.
- /// </param>
- protected virtual void Dispose(bool disposing)
- {
- if (!disposing) return;
-
- Connection.Close();
- Connection.Dispose();
-
- TransmissionArgsPool.Dispose();
- }
-
- /// <summary>
- /// Delegate method to handle asynchronous network IO completion via the <see cref="SocketAsyncEventArgs.Completed" /> event.
- /// </summary>
- /// <param name="sender">
- /// The object which raised the event.
- /// </param>
- /// <param name="args">
- /// The <see cref="SocketAsyncEventArgs" /> instance associated with the asynchronous network IO.
- /// </param>
- protected abstract void HandleIoCompleted(object sender, SocketAsyncEventArgs args);
-
- /// <summary>
- /// Delegate method used to reset used <see cref="SocketAsyncEventArgs" /> instances for later reuse by the <see cref="TransmissionArgsPool" />.
- /// </summary>
- /// <param name="args">
- /// The <see cref="SocketAsyncEventArgs" /> instance that should be reset.
- /// </param>
- protected abstract void ResetTransmissionArgs(SocketAsyncEventArgs args);
-
- /// <summary>
- /// Binds the underlying socket.
- /// </summary>
- /// <param name="localEndPoint">
- /// The end point to which the socket should be bound.
- /// </param>
- public void Bind(in EndPoint localEndPoint)
- {
- Connection.Bind(localEndPoint);
- }
-
- /// <inheritdoc />
- public void Dispose()
- {
- Dispose(true);
- GC.SuppressFinalize(this);
- }
-
- /// <summary>
- /// Shuts down the underlying socket.
- /// </summary>
- /// <param name="how">
- /// Which socket transmission functions should be shut down on the socket.
- /// </param>
- public void Shutdown(SocketShutdown how)
- {
- try
- {
- Connection.Shutdown(how);
- }
- catch (SocketException) { }
- }
- }
-}
-\ No newline at end of file
diff --git a/NetSharp/NetSharp/Sockets/SocketConnectionBase.cs b/NetSharp/NetSharp/Sockets/SocketConnectionBase.cs
@@ -0,0 +1,175 @@
+using NetSharp.Utils;
+
+using System;
+using System.Buffers;
+using System.Net;
+using System.Net.Sockets;
+
+namespace NetSharp.Sockets
+{
+ /// <summary>
+ /// Abstract base class for client and server wrappers around existing <see cref="Socket"/> objects.
+ /// </summary>
+ public abstract class SocketConnectionBase : IDisposable
+ {
+ /// <summary>
+ /// The maximum size of buffer that can be rented from the pool.
+ /// </summary>
+ protected readonly int MaxBufferSize;
+
+ /// <summary>
+ /// Pools arrays to function as temporary buffers during network read/write operations.
+ /// </summary>
+ protected readonly ArrayPool<byte> BufferPool;
+
+ /// <summary>
+ /// Pools <see cref="SocketAsyncEventArgs" /> objects for use during network read/write operations and calls to
+ /// <see cref="Socket" />.XXXAsync( <see cref="SocketAsyncEventArgs" />) methods.
+ /// </summary>
+ protected readonly SlimObjectPool<SocketAsyncEventArgs> ArgsPool;
+
+ /// <summary>
+ /// The underlying <see cref="Socket" /> which provides access to network operations.
+ /// </summary>
+ protected Socket Connection;
+
+ /// <summary>
+ /// Constructs a new instance of the <see cref="SocketConnectionBase" /> class.
+ /// </summary>
+ /// <param name="rawConnection">
+ /// The underlying <see cref="Socket"/> object which should be wrapped by this instance.
+ /// </param>
+ /// <param name="pooledBufferMaxSize">
+ /// The maximum size in bytes of buffers held in the buffer pool.
+ /// </param>
+ /// <param name="preallocatedTransmissionArgs">
+ /// The number of <see cref="SocketAsyncEventArgs" /> objects to initially preallocate.
+ /// </param>
+ private protected SocketConnectionBase(ref Socket rawConnection, int pooledBufferMaxSize, ushort preallocatedTransmissionArgs)
+ {
+ Connection = rawConnection;
+
+ MaxBufferSize = pooledBufferMaxSize;
+ BufferPool = ArrayPool<byte>.Create(MaxBufferSize, 1000);
+
+ ArgsPool = new SlimObjectPool<SocketAsyncEventArgs>(CreateTransmissionArgs,
+ ResetTransmissionArgs, DestroyTransmissionArgs, CanTransmissionArgsBeReused);
+
+ // TODO refactor into a cleaner structure, with a better method of seeding the object pool
+ for (ushort i = 0; i < preallocatedTransmissionArgs; i++)
+ {
+ SocketAsyncEventArgs args = CreateTransmissionArgs();
+
+ ArgsPool.Return(args);
+ }
+ }
+
+ /// <summary>
+ /// The local endpoint to which the underlying <see cref="Socket" /> is bound.
+ /// </summary>
+ public EndPoint LocalEndPoint
+ {
+ get { return Connection.LocalEndPoint; }
+ }
+
+ /// <summary>
+ /// Delegate method used to check whether the given used <see cref="SocketAsyncEventArgs" /> instance can be reused by the
+ /// <see cref="ArgsPool" />. If this method returns <c>true</c>, <see cref="ResetTransmissionArgs" /> is called on the given
+ /// <paramref name="args" />. Otherwise, <see cref="DestroyTransmissionArgs" /> is called.
+ /// </summary>
+ /// <param name="args">
+ /// The <see cref="SocketAsyncEventArgs" /> instance to check.
+ /// </param>
+ /// <returns>
+ /// Whether the given <paramref name="args" /> should be reset and reused, or should be destroyed.
+ /// </returns>
+ protected abstract bool CanTransmissionArgsBeReused(in SocketAsyncEventArgs args);
+
+ /// <summary>
+ /// Delegate method used to construct fresh <see cref="SocketAsyncEventArgs" /> instances for use in the <see cref="ArgsPool" />.
+ /// The resulting instance should register <see cref="HandleIoCompleted" /> as an event handler for the
+ /// <see cref="SocketAsyncEventArgs.Completed" /> event.
+ /// </summary>
+ /// <returns>
+ /// The configured <see cref="SocketAsyncEventArgs" /> instance.
+ /// </returns>
+ protected abstract SocketAsyncEventArgs CreateTransmissionArgs();
+
+ /// <summary>
+ /// Delegate method to destroy used <see cref="SocketAsyncEventArgs" /> instances that cannot be reused by the
+ /// <see cref="ArgsPool" />. This method should deregister <see cref="HandleIoCompleted" /> as an event handler for the
+ /// <see cref="SocketAsyncEventArgs.Completed" /> event.
+ /// </summary>
+ /// <param name="remoteConnectionArgs">
+ /// The <see cref="SocketAsyncEventArgs" /> which should be destroyed.
+ /// </param>
+ protected abstract void DestroyTransmissionArgs(SocketAsyncEventArgs remoteConnectionArgs);
+
+ /// <summary>
+ /// Disposes of managed and unmanaged resources used by the <see cref="SocketConnectionBase" /> class.
+ /// </summary>
+ /// <param name="disposing">
+ /// Whether this call was made by a call to <see cref="Dispose()" />.
+ /// </param>
+ protected virtual void Dispose(bool disposing)
+ {
+ if (!disposing) return;
+
+ ArgsPool.Dispose();
+ }
+
+ /// <summary>
+ /// Delegate method to handle asynchronous network IO completion via the <see cref="SocketAsyncEventArgs.Completed" /> event.
+ /// </summary>
+ /// <param name="sender">
+ /// The object which raised the event.
+ /// </param>
+ /// <param name="args">
+ /// The <see cref="SocketAsyncEventArgs" /> instance associated with the asynchronous network IO.
+ /// </param>
+ protected abstract void HandleIoCompleted(object sender, SocketAsyncEventArgs args);
+
+ /// <summary>
+ /// Delegate method used to reset used <see cref="SocketAsyncEventArgs" /> instances for later reuse by the <see cref="ArgsPool" />.
+ /// </summary>
+ /// <param name="args">
+ /// The <see cref="SocketAsyncEventArgs" /> instance that should be reset.
+ /// </param>
+ protected abstract void ResetTransmissionArgs(ref SocketAsyncEventArgs args);
+
+ /// <summary>
+ /// Binds the underlying socket.
+ /// </summary>
+ /// <param name="localEndPoint">
+ /// The end point to which the socket should be bound.
+ /// </param>
+ public void Bind(in EndPoint localEndPoint)
+ {
+ Connection.Bind(localEndPoint);
+ }
+
+ /// <inheritdoc />
+ public void Dispose()
+ {
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+
+ /// <summary>
+ /// Shuts down the underlying socket.
+ /// </summary>
+ /// <param name="how">
+ /// Which socket transmission functions should be shut down on the socket.
+ /// </param>
+ public void Shutdown(SocketShutdown how)
+ {
+ try
+ {
+ Connection.Shutdown(how);
+ }
+ catch (SocketException) { }
+
+ Connection.Close();
+ }
+ }
+}
+\ No newline at end of file
diff --git a/NetSharp/NetSharp/Sockets/SocketServer.cs b/NetSharp/NetSharp/Sockets/SocketServer.cs
@@ -1,90 +0,0 @@
-using NetSharp.Packets;
-
-using System.Net;
-using System.Net.Sockets;
-using System.Threading;
-using System.Threading.Tasks;
-
-namespace NetSharp.Sockets
-{
- /// <summary>
- /// Represents a method for serving request packets. This method should not throw any errors.
- /// </summary>
- /// <param name="requestPacket">
- /// The request packet received by the server.
- /// </param>
- /// <param name="clientEndPoint">
- /// The client from which the packet was received.
- /// </param>
- /// <returns>
- /// The response packet which should be sent out to the client. If no packet should be sent out, this method must return <see cref="NetworkPacket.NullPacket" />.
- /// </returns>
- public delegate NetworkPacket SocketServerPacketHandler(in NetworkPacket requestPacket, in EndPoint clientEndPoint);
-
- /// <summary>
- /// Abstract base class for servers.
- /// </summary>
- public abstract class SocketServer : SocketConnection
- {
- /// <summary>
- /// The packet handler delegate to use to respond to incoming requests.
- /// </summary>
- protected readonly SocketServerPacketHandler PacketHandler;
-
- /// <summary>
- /// Constructs a new instance of the <see cref="SocketServer" /> class.
- /// </summary>
- /// <param name="connectionAddressFamily">
- /// The address family that the underlying connection should use.
- /// </param>
- /// <param name="connectionSocketType">
- /// The socket type that the underlying connection should use.
- /// </param>
- /// <param name="connectionProtocolType">
- /// The protocol type that the underlying connection should use.
- /// </param>
- /// <param name="packetHandler">
- /// The packet handler delegate to use to respond to incoming requests.
- /// </param>
- /// <param name="pooledBufferMaxSize">
- /// The maximum size in bytes of buffers held in the buffer pool.
- /// </param>
- /// <param name="preallocatedTransmissionArgs">
- /// The number of transmission args to preallocate.
- /// </param>
- protected SocketServer(in AddressFamily connectionAddressFamily, in SocketType connectionSocketType, in ProtocolType connectionProtocolType,
- in SocketServerPacketHandler packetHandler, in int pooledBufferMaxSize, in ushort preallocatedTransmissionArgs)
- : base(in connectionAddressFamily, in connectionSocketType, in connectionProtocolType, pooledBufferMaxSize, preallocatedTransmissionArgs)
- {
- PacketHandler = packetHandler;
- }
-
- /// <summary>
- /// The default request packet handler for servers. Simply echoes back any received packets.
- /// </summary>
- /// <param name="request">
- /// The request packet that was received.
- /// </param>
- /// <param name="remoteEndPoint">
- /// The client from which the packet was received.
- /// </param>
- /// <returns>
- /// The received packet.
- /// </returns>
- public static NetworkPacket DefaultPacketHandler(in NetworkPacket request, in EndPoint remoteEndPoint)
- {
- return request;
- }
-
- /// <summary>
- /// Runs the server, handling requests from clients, until the <paramref name="cancellationToken" /> has its cancellation requested.
- /// </summary>
- /// <param name="cancellationToken">
- /// The <see cref="CancellationToken" /> upon whose cancellation the server should shut down.
- /// </param>
- /// <returns>
- /// A <see cref="Task" /> representing the server's execution.
- /// </returns>
- public abstract Task RunAsync(CancellationToken cancellationToken = default);
- }
-}
-\ No newline at end of file
diff --git a/NetSharp/NetSharp/Sockets/Stream/StreamSocketClient.cs b/NetSharp/NetSharp/Sockets/Stream/StreamSocketClient.cs
@@ -40,14 +40,20 @@ namespace NetSharp.Sockets.Stream
//TODO address the need to handle series of network packets, not just single packets
//TODO document class
- public sealed class StreamSocketClient : SocketClient
+ public sealed class StreamSocketClient : RawSocketClient
{
private readonly StreamSocketClientOptions clientOptions;
- public StreamSocketClient(in AddressFamily connectionAddressFamily, in ProtocolType connectionProtocolType,
- in StreamSocketClientOptions? clientOptions = null) : base(in connectionAddressFamily, SocketType.Stream, in connectionProtocolType,
- NetworkPacket.TotalSize, clientOptions?.PreallocatedTransmissionArgs ?? StreamSocketClientOptions.Defaults.PreallocatedTransmissionArgs)
+ public StreamSocketClient(ref Socket rawConnection, in StreamSocketClientOptions? clientOptions = null)
+ : base(ref rawConnection,
+ NetworkPacket.TotalSize,
+ clientOptions?.PreallocatedTransmissionArgs ?? StreamSocketClientOptions.Defaults.PreallocatedTransmissionArgs)
{
+ if (rawConnection.SocketType != SocketType.Stream)
+ {
+ throw new ArgumentException($"Only {SocketType.Stream} is supported!", nameof(rawConnection));
+ }
+
this.clientOptions = clientOptions ?? StreamSocketClientOptions.Defaults;
}
@@ -78,7 +84,7 @@ namespace NetSharp.Sockets.Stream
break;
}
- TransmissionArgsPool.Return(args);
+ ArgsPool.Return(args);
}
private void CompleteDisconnect(SocketAsyncEventArgs args)
@@ -103,7 +109,7 @@ namespace NetSharp.Sockets.Stream
break;
}
- TransmissionArgsPool.Return(args);
+ ArgsPool.Return(args);
}
private void CompleteReceive(SocketAsyncEventArgs args)
@@ -154,7 +160,7 @@ namespace NetSharp.Sockets.Stream
break;
}
- TransmissionArgsPool.Return(args);
+ ArgsPool.Return(args);
}
private void CompleteSend(SocketAsyncEventArgs args)
@@ -206,7 +212,7 @@ namespace NetSharp.Sockets.Stream
}
BufferPool.Return(sendToken.RentedBuffer, true);
- TransmissionArgsPool.Return(args);
+ ArgsPool.Return(args);
}
/// <inheritdoc />
@@ -264,7 +270,7 @@ namespace NetSharp.Sockets.Stream
}
/// <inheritdoc />
- protected override void ResetTransmissionArgs(SocketAsyncEventArgs args)
+ protected override void ResetTransmissionArgs(ref SocketAsyncEventArgs args)
{
}
@@ -277,7 +283,7 @@ namespace NetSharp.Sockets.Stream
{
TaskCompletionSource<bool> tcs = new TaskCompletionSource<bool>();
- SocketAsyncEventArgs args = TransmissionArgsPool.Rent();
+ SocketAsyncEventArgs args = ArgsPool.Rent();
if (cancellationToken == default)
{
@@ -305,7 +311,7 @@ namespace NetSharp.Sockets.Stream
cancellationRegistration.Dispose();
}
- TransmissionArgsPool.Return(args);
+ ArgsPool.Return(args);
return new ValueTask();
}
@@ -325,44 +331,22 @@ namespace NetSharp.Sockets.Stream
}
/// <inheritdoc />
- public override ValueTask<TransmissionResult> ReceiveAsync(in EndPoint remoteEndPoint, Memory<byte> receiveBuffer, SocketFlags flags = SocketFlags.None,
- CancellationToken cancellationToken = default)
+ public override ValueTask<TransmissionResult> ReceiveAsync(in EndPoint remoteEndPoint, Memory<byte> receiveBuffer, SocketFlags flags = SocketFlags.None)
{
TaskCompletionSource<TransmissionResult> tcs = new TaskCompletionSource<TransmissionResult>();
- SocketAsyncEventArgs args = TransmissionArgsPool.Rent();
+ SocketAsyncEventArgs args = ArgsPool.Rent();
args.SetBuffer(receiveBuffer);
args.SocketFlags = flags;
- args.UserToken = new AsyncReceiveToken(in tcs, in cancellationToken);
-
- if (cancellationToken == default)
- {
- if (Connection.ReceiveAsync(args)) return new ValueTask<TransmissionResult>(tcs.Task);
- }
- else
- {
- // TODO find out why the fricc we leak memory
- CancellationTokenRegistration cancellationRegistration =
- cancellationToken.Register(CancelAsyncReceiveCallback, args);
-
- if (Connection.ReceiveAsync(args))
- return new ValueTask<TransmissionResult>(
- tcs.Task.ContinueWith((task, state) =>
- {
- ((CancellationTokenRegistration)state).Dispose();
+ args.UserToken = new AsyncReceiveToken(in tcs, CancellationToken.None);
- return task.Result;
- }, cancellationRegistration, CancellationToken.None)
- );
-
- cancellationRegistration.Dispose();
- }
+ if (Connection.ReceiveAsync(args)) return new ValueTask<TransmissionResult>(tcs.Task);
TransmissionResult result = new TransmissionResult(in args);
- TransmissionArgsPool.Return(args);
+ ArgsPool.Return(args);
return new ValueTask<TransmissionResult>(result);
}
@@ -382,12 +366,11 @@ namespace NetSharp.Sockets.Stream
}
/// <inheritdoc />
- public override ValueTask<TransmissionResult> SendAsync(in EndPoint remoteEndPoint, ReadOnlyMemory<byte> sendBuffer, SocketFlags flags = SocketFlags.None,
- CancellationToken cancellationToken = default)
+ public override ValueTask<TransmissionResult> SendAsync(in EndPoint remoteEndPoint, ReadOnlyMemory<byte> sendBuffer, SocketFlags flags = SocketFlags.None)
{
TaskCompletionSource<TransmissionResult> tcs = new TaskCompletionSource<TransmissionResult>();
- SocketAsyncEventArgs args = TransmissionArgsPool.Rent();
+ SocketAsyncEventArgs args = ArgsPool.Rent();
byte[] transmissionBuffer = BufferPool.Rent(sendBuffer.Length);
sendBuffer.CopyTo(transmissionBuffer);
@@ -395,34 +378,13 @@ namespace NetSharp.Sockets.Stream
args.SetBuffer(transmissionBuffer);
args.SocketFlags = flags;
- args.UserToken = new AsyncSendToken(in tcs, in transmissionBuffer, in cancellationToken);
-
- if (cancellationToken == default)
- {
- if (Connection.SendAsync(args)) return new ValueTask<TransmissionResult>(tcs.Task);
- }
- else
- {
- // TODO find out why the fricc we leak memory
- CancellationTokenRegistration cancellationRegistration =
- cancellationToken.Register(CancelAsyncSendCallback, args);
+ args.UserToken = new AsyncSendToken(in tcs, ref transmissionBuffer, CancellationToken.None);
- if (Connection.SendAsync(args))
- return new ValueTask<TransmissionResult>(
- tcs.Task.ContinueWith((task, state) =>
- {
- ((CancellationTokenRegistration)state).Dispose();
-
- return task.Result;
- }, cancellationRegistration, CancellationToken.None)
- );
-
- cancellationRegistration.Dispose();
- }
+ if (Connection.SendAsync(args)) return new ValueTask<TransmissionResult>(tcs.Task);
TransmissionResult result = new TransmissionResult(in args);
- TransmissionArgsPool.Return(args);
+ ArgsPool.Return(args);
return new ValueTask<TransmissionResult>(result);
}
diff --git a/NetSharp/NetSharp/Sockets/Stream/StreamSocketServer.cs b/NetSharp/NetSharp/Sockets/Stream/StreamSocketServer.cs
@@ -49,7 +49,7 @@ namespace NetSharp.Sockets.Stream
//TODO address the need to handle series of network packets, not just single packets
//TODO document class
- public sealed class StreamSocketServer : SocketServer
+ public sealed class StreamSocketServer : RawSocketServer
{
private readonly StreamSocketServerOptions serverOptions;
@@ -60,11 +60,17 @@ namespace NetSharp.Sockets.Stream
/// Additional options to configure the server.
/// </param>
/// <inheritdoc />
- public StreamSocketServer(in AddressFamily connectionAddressFamily, in ProtocolType connectionProtocolType,
- in SocketServerPacketHandler packetHandler, in StreamSocketServerOptions? serverOptions = null)
- : base(in connectionAddressFamily, SocketType.Stream, in connectionProtocolType, in packetHandler,
- NetworkPacket.TotalSize, serverOptions?.PreallocatedTransmissionArgs ?? StreamSocketServerOptions.Defaults.PreallocatedTransmissionArgs)
+ public StreamSocketServer(ref Socket rawConnection, in RawRequestPacketHandler packetHandler, in StreamSocketServerOptions? serverOptions = null)
+ : base(ref rawConnection,
+ NetworkPacket.TotalSize,
+ serverOptions?.PreallocatedTransmissionArgs ?? StreamSocketServerOptions.Defaults.PreallocatedTransmissionArgs,
+ packetHandler)
{
+ if (rawConnection.SocketType != SocketType.Stream)
+ {
+ throw new ArgumentException($"Only {SocketType.Stream} is supported!", nameof(rawConnection));
+ }
+
this.serverOptions = serverOptions ?? StreamSocketServerOptions.Defaults;
}
@@ -79,7 +85,7 @@ namespace NetSharp.Sockets.Stream
if (operationPending) return;
- SocketAsyncEventArgs newAcceptArgs = TransmissionArgsPool.Rent();
+ SocketAsyncEventArgs newAcceptArgs = ArgsPool.Rent();
Accept(newAcceptArgs); // start a new accept operation to not miss any clients
@@ -91,7 +97,7 @@ namespace NetSharp.Sockets.Stream
RemoteStreamClientToken clientToken = (RemoteStreamClientToken)clientArgs.UserToken;
clientToken.Dispose();
- TransmissionArgsPool.Return(clientArgs);
+ ArgsPool.Return(clientArgs);
}
private void CompleteAccept(SocketAsyncEventArgs connectedClientArgs)
@@ -114,19 +120,17 @@ namespace NetSharp.Sockets.Stream
if (clientArgs.BytesTransferred == NetworkPacket.TotalSize)
{
// buffer was fully received
+ byte[] responseBuffer = BufferPool.Rent(MaxBufferSize);
- NetworkPacket.Deserialise(receiveToken.RentedBuffer, out NetworkPacket request);
+ bool responseExists = PacketHandler(clientArgs.RemoteEndPoint, receiveToken.RentedBuffer, responseBuffer);
+ BufferPool.Return(receiveToken.RentedBuffer, true); // at this point the request buffer can be returned
- NetworkPacket response = PacketHandler(in request, clientArgs.RemoteEndPoint);
+ //NetworkPacket.Deserialise(receiveToken.RentedBuffer, out NetworkPacket request);
+ //NetworkPacket response = PacketHandler(in request, clientArgs.RemoteEndPoint);
- if (!response.Equals(NetworkPacket.NullPacket))
+ if (responseExists)
{
- byte[] responseBuffer = BufferPool.Rent(NetworkPacket.TotalSize);
- Memory<byte> responseBufferMemory = new Memory<byte>(responseBuffer);
-
- NetworkPacket.Serialise(response, responseBufferMemory);
-
- BufferPool.Return(receiveToken.RentedBuffer, true); // at this point the request buffer can be returned
+ //NetworkPacket.Serialise(response, responseBufferMemory);
receiveToken.RentedBuffer = responseBuffer;
clientArgs.SetBuffer(responseBuffer, 0, NetworkPacket.TotalSize);
@@ -135,10 +139,10 @@ namespace NetSharp.Sockets.Stream
}
else
{
- BufferPool.Return(receiveToken.RentedBuffer, true); // at this point the request buffer can be returned
-
- Receive(clientArgs);
+ BufferPool.Return(responseBuffer, true);
}
+
+ Receive(clientArgs);
}
else if (NetworkPacket.TotalSize > clientArgs.BytesTransferred && clientArgs.BytesTransferred > 0)
{
@@ -262,7 +266,7 @@ namespace NetSharp.Sockets.Stream
switch (args.LastOperation)
{
case SocketAsyncOperation.Accept:
- SocketAsyncEventArgs newAcceptArgs = TransmissionArgsPool.Rent();
+ SocketAsyncEventArgs newAcceptArgs = ArgsPool.Rent();
Accept(newAcceptArgs); // start a new accept operation to not miss any clients
@@ -286,7 +290,7 @@ namespace NetSharp.Sockets.Stream
}
/// <inheritdoc />
- protected override void ResetTransmissionArgs(SocketAsyncEventArgs args)
+ protected override void ResetTransmissionArgs(ref SocketAsyncEventArgs args)
{
}
@@ -297,7 +301,7 @@ namespace NetSharp.Sockets.Stream
for (int i = 0; i < serverOptions.ConcurrentAcceptCalls; i++)
{
- SocketAsyncEventArgs acceptArgs = TransmissionArgsPool.Rent();
+ SocketAsyncEventArgs acceptArgs = ArgsPool.Rent();
Accept(acceptArgs);
}
diff --git a/NetSharp/NetSharp/Utils/SlimObjectPool.cs b/NetSharp/NetSharp/Utils/SlimObjectPool.cs
@@ -109,7 +109,7 @@ namespace NetSharp.Utils
/// <param name="instance">
/// The instance which should be reset.
/// </param>
- public delegate void ResetObjectDelegate(T instance);
+ public delegate void ResetObjectDelegate(ref T instance);
/// <inheritdoc />
public void Dispose()
@@ -141,7 +141,7 @@ namespace NetSharp.Utils
{
if (canObjectBeRebufferedPredicate(instance))
{
- resetObjectDelegate(instance);
+ resetObjectDelegate(ref instance);
objectBuffer.TryAdd(instance);
}
diff --git a/NetSharp/NetSharpExamples/BenchmarkHelper.cs b/NetSharp/NetSharpExamples/BenchmarkHelper.cs
@@ -5,24 +5,24 @@ namespace NetSharpExamples
{
public class BenchmarkHelper
{
- private readonly Stopwatch bandwidthStopwatch = new Stopwatch();
- private readonly Stopwatch rttStopwatch = new Stopwatch();
+ private readonly Stopwatch stopwatch = new Stopwatch();
+ private long lastTicksSnapshot = 0, lastMsSnapshot = 0;
private long minRttMs = int.MaxValue, maxRttMs = int.MinValue;
private long minRttTicks = int.MaxValue, maxRttTicks = int.MinValue;
public long RttMs
{
- get { return rttStopwatch.ElapsedMilliseconds; }
+ get { return stopwatch.ElapsedMilliseconds; }
}
public long RttTicks
{
- get { return rttStopwatch.ElapsedTicks; }
+ get { return stopwatch.ElapsedTicks; }
}
public double CalcBandwidth(long sentPacketCount, long packetSize)
{
- long millis = bandwidthStopwatch.ElapsedMilliseconds;
+ long millis = stopwatch.ElapsedMilliseconds;
double megabytes = sentPacketCount * packetSize / 1_000_000.0;
double bandwidth = megabytes / (millis / 1000.0);
@@ -31,7 +31,7 @@ namespace NetSharpExamples
public void PrintBandwidthStats(int clientId, long sentPacketCount, long packetSize)
{
- long millis = bandwidthStopwatch.ElapsedMilliseconds;
+ long millis = stopwatch.ElapsedMilliseconds;
double megabytes = sentPacketCount * packetSize / 1_000_000.0;
double bandwidth = megabytes / (millis / 1000.0);
@@ -51,53 +51,46 @@ namespace NetSharpExamples
}
}
- public void ResetBandwidthStopwatch()
+ public void ResetStopwatch()
{
- bandwidthStopwatch.Reset();
- }
-
- public void ResetRttStopwatch()
- {
- rttStopwatch.Reset();
- }
-
- public void StartBandwidthStopwatch()
- {
- bandwidthStopwatch.Start();
- }
-
- public void StartRttStopwatch()
- {
- rttStopwatch.Start();
- }
+ lastTicksSnapshot = 0;
+ lastMsSnapshot = 0;
- public void StopBandwidthStopwatch()
- {
- bandwidthStopwatch.Stop();
+ stopwatch.Reset();
}
- public void StopRttStopwatch()
+ public void SnapshotRttStats()
{
- rttStopwatch.Stop();
- }
+ long elapsedTicksSnapshot = stopwatch.ElapsedTicks, elapsedMsSnapshot = stopwatch.ElapsedMilliseconds;
- public void UpdateRttStats(int clientId)
- {
- minRttTicks = rttStopwatch.ElapsedTicks < minRttTicks
- ? rttStopwatch.ElapsedTicks
+ minRttTicks = elapsedTicksSnapshot - lastTicksSnapshot < minRttTicks
+ ? elapsedTicksSnapshot - lastTicksSnapshot
: minRttTicks;
- minRttMs = rttStopwatch.ElapsedMilliseconds < minRttMs
- ? rttStopwatch.ElapsedMilliseconds
+ minRttMs = elapsedMsSnapshot - lastMsSnapshot < minRttMs
+ ? elapsedMsSnapshot - lastMsSnapshot
: minRttMs;
- maxRttTicks = rttStopwatch.ElapsedTicks > maxRttTicks
- ? rttStopwatch.ElapsedTicks
+ maxRttTicks = elapsedTicksSnapshot - lastTicksSnapshot > maxRttTicks
+ ? elapsedTicksSnapshot - lastTicksSnapshot
: maxRttTicks;
- maxRttMs = rttStopwatch.ElapsedMilliseconds > maxRttMs
- ? rttStopwatch.ElapsedMilliseconds
+ maxRttMs = elapsedMsSnapshot - lastMsSnapshot > maxRttMs
+ ? elapsedMsSnapshot - lastMsSnapshot
: maxRttMs;
+
+ lastTicksSnapshot = elapsedTicksSnapshot;
+ lastMsSnapshot = elapsedMsSnapshot;
+ }
+
+ public void StartStopwatch()
+ {
+ stopwatch.Start();
+ }
+
+ public void StopStopwatch()
+ {
+ stopwatch.Stop();
}
}
}
\ No newline at end of file
diff --git a/NetSharp/NetSharpExamples/Benchmarks/DatagramNetworkReaderBenchmark.cs b/NetSharp/NetSharpExamples/Benchmarks/DatagramNetworkReaderBenchmark.cs
@@ -0,0 +1,109 @@
+using System;
+using System.Linq;
+using System.Net;
+using System.Net.Sockets;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+using NetSharp;
+
+namespace NetSharpExamples.Benchmarks
+{
+ public class DatagramNetworkReaderBenchmark : INetSharpExample
+ {
+ private const int PacketSize = 8192, PacketCount = 1_000_000, ClientCount = 12;
+
+ public static readonly EndPoint ClientEndPoint = new IPEndPoint(IPAddress.Loopback, 0);
+
+ public static readonly EndPoint ServerEndPoint = new IPEndPoint(IPAddress.Loopback, 12349);
+
+ public static readonly Encoding ServerEncoding = Encoding.UTF8;
+
+ private double[] ClientBandwidths;
+
+ /// <inheritdoc />
+ public string Name { get; } = "Datagram Network Reader Benchmark";
+
+ private Task BenchmarkClientTask(object idObj)
+ {
+ try
+ {
+ int id = (int)idObj;
+
+ BenchmarkHelper benchmarkHelper = new BenchmarkHelper();
+
+ Socket clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
+ clientSocket.Bind(ClientEndPoint);
+
+ byte[] sendBuffer = new byte[PacketSize];
+ byte[] receiveBuffer = new byte[PacketSize];
+
+ EndPoint remoteEndPoint = ServerEndPoint;
+
+ lock (typeof(Console))
+ {
+ Console.WriteLine($"[Client {id}] Starting client; sending messages to {remoteEndPoint}");
+ }
+
+ for (int i = 0; i < PacketCount; i++)
+ {
+ byte[] packetBuffer = ServerEncoding.GetBytes($"[Client {id}] Hello World! (Packet {i})");
+ packetBuffer.CopyTo(sendBuffer, 0);
+
+ benchmarkHelper.StartStopwatch();
+ int sentBytes = clientSocket.SendTo(sendBuffer, remoteEndPoint);
+
+ int receivedBytes = clientSocket.ReceiveFrom(receiveBuffer, ref remoteEndPoint);
+ benchmarkHelper.StopStopwatch();
+
+ benchmarkHelper.SnapshotRttStats();
+ }
+
+ benchmarkHelper.PrintBandwidthStats(id, PacketCount, PacketSize);
+ benchmarkHelper.PrintRttStats(id);
+
+ ClientBandwidths[id] = benchmarkHelper.CalcBandwidth(PacketCount, PacketSize);
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine(ex);
+ }
+
+ return Task.CompletedTask;
+ }
+
+ /// <inheritdoc />
+ public async Task RunAsync()
+ {
+ EndPoint defaultRemoteEndPoint = new IPEndPoint(IPAddress.Any, 0);
+
+ Socket rawSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
+ rawSocket.Bind(ServerEndPoint);
+ using DatagramNetworkReader reader = new DatagramNetworkReader(ref rawSocket, RequestHandler, defaultRemoteEndPoint, PacketSize);
+ reader.Start(ClientCount);
+
+ ClientBandwidths = new double[ClientCount];
+ Task[] clientTasks = new Task[ClientCount];
+ for (int i = 0; i < clientTasks.Length; i++)
+ {
+ clientTasks[i] = Task.Factory.StartNew(BenchmarkClientTask, i, TaskCreationOptions.LongRunning);
+ }
+
+ await Task.WhenAll(clientTasks);
+
+ Console.WriteLine($"Total estimated bandwidth: {ClientBandwidths.Sum():F5}");
+
+ reader.Stop();
+
+ rawSocket.Close();
+ rawSocket.Dispose();
+
+ Console.WriteLine($"UDP Server Benchmark finished!");
+ }
+
+ private static bool RequestHandler(in EndPoint remoteEndPoint, ReadOnlyMemory<byte> requestBuffer, Memory<byte> responseBuffer)
+ {
+ return requestBuffer.TryCopyTo(responseBuffer);
+ }
+ }
+}
+\ No newline at end of file
diff --git a/NetSharp/NetSharpExamples/Benchmarks/TcpSocketClientAsyncBenchmark.cs b/NetSharp/NetSharpExamples/Benchmarks/TcpSocketClientAsyncBenchmark.cs
@@ -83,7 +83,8 @@ namespace NetSharpExamples.Benchmarks
BenchmarkHelper benchmarkHelper = new BenchmarkHelper();
StreamSocketClientOptions clientOptions = new StreamSocketClientOptions((ushort)2);
- using StreamSocketClient client = new StreamSocketClient(AddressFamily.InterNetwork, ProtocolType.Tcp, clientOptions);
+ Socket rawSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
+ using StreamSocketClient client = new StreamSocketClient(ref rawSocket, clientOptions);
await client.ConnectAsync(in ServerEndPoint);
@@ -95,16 +96,13 @@ namespace NetSharpExamples.Benchmarks
byte[] packetBuffer = Encoding.UTF8.GetBytes($"[Client 0] Hello World! (Packet {i})");
packetBuffer.CopyTo(sendBuffer, 0);
- benchmarkHelper.StartBandwidthStopwatch();
- benchmarkHelper.StartRttStopwatch();
+ benchmarkHelper.StartStopwatch();
TransmissionResult sendResult = await client.SendAsync(in ServerEndPoint, sendBuffer);
TransmissionResult receiveResult = await client.ReceiveAsync(in ServerEndPoint, receiveBuffer);
- benchmarkHelper.StopRttStopwatch();
- benchmarkHelper.StopBandwidthStopwatch();
+ benchmarkHelper.StopStopwatch();
- benchmarkHelper.UpdateRttStats(0);
- benchmarkHelper.ResetRttStopwatch();
+ benchmarkHelper.SnapshotRttStats();
}
benchmarkHelper.PrintBandwidthStats(0, PacketCount, NetworkPacket.TotalSize);
diff --git a/NetSharp/NetSharpExamples/Benchmarks/TcpSocketClientSyncBenchmark.cs b/NetSharp/NetSharpExamples/Benchmarks/TcpSocketClientSyncBenchmark.cs
@@ -83,7 +83,8 @@ namespace NetSharpExamples.Benchmarks
BenchmarkHelper benchmarkHelper = new BenchmarkHelper();
StreamSocketClientOptions clientOptions = new StreamSocketClientOptions((ushort)2);
- using StreamSocketClient client = new StreamSocketClient(AddressFamily.InterNetwork, ProtocolType.Tcp, clientOptions);
+ Socket rawSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
+ using StreamSocketClient client = new StreamSocketClient(ref rawSocket, clientOptions);
client.Connect(in ServerEndPoint);
@@ -95,16 +96,13 @@ namespace NetSharpExamples.Benchmarks
byte[] packetBuffer = Encoding.UTF8.GetBytes($"[Client 0] Hello World! (Packet {i})");
packetBuffer.CopyTo(sendBuffer, 0);
- benchmarkHelper.StartBandwidthStopwatch();
- benchmarkHelper.StartRttStopwatch();
+ benchmarkHelper.StartStopwatch();
TransmissionResult sendResult = client.Send(in ServerEndPoint, sendBuffer);
TransmissionResult receiveResult = client.Receive(in ServerEndPoint, receiveBuffer);
- benchmarkHelper.StopRttStopwatch();
- benchmarkHelper.StopBandwidthStopwatch();
-
- benchmarkHelper.UpdateRttStats(0);
- benchmarkHelper.ResetRttStopwatch();
+ benchmarkHelper.StopStopwatch();
+
+ benchmarkHelper.SnapshotRttStats();
}
benchmarkHelper.PrintBandwidthStats(0, PacketCount, NetworkPacket.TotalSize);
diff --git a/NetSharp/NetSharpExamples/Benchmarks/TcpSocketServerBenchmark.cs b/NetSharp/NetSharpExamples/Benchmarks/TcpSocketServerBenchmark.cs
@@ -52,8 +52,7 @@ namespace NetSharpExamples.Benchmarks
byte[] packetBuffer = Encoding.UTF8.GetBytes($"[Client {id}] Hello World! (Packet {i})");
packetBuffer.CopyTo(sendBuffer, 0);
- benchmarkHelper.StartBandwidthStopwatch();
- benchmarkHelper.StartRttStopwatch();
+ benchmarkHelper.StartStopwatch();
int totalSent = 0;
do
@@ -79,11 +78,9 @@ namespace NetSharpExamples.Benchmarks
break;
}
- benchmarkHelper.StopRttStopwatch();
- benchmarkHelper.StopBandwidthStopwatch();
+ benchmarkHelper.StopStopwatch();
- benchmarkHelper.UpdateRttStats(id);
- benchmarkHelper.ResetRttStopwatch();
+ benchmarkHelper.SnapshotRttStats();
}
clientSocket.Disconnect(true);
@@ -112,9 +109,8 @@ namespace NetSharpExamples.Benchmarks
}
StreamSocketServerOptions serverOptions = new StreamSocketServerOptions(clientCount, (ushort)clientCount);
-
- StreamSocketServer server = new StreamSocketServer(AddressFamily.InterNetwork, ProtocolType.Tcp,
- SocketServer.DefaultPacketHandler, serverOptions);
+ Socket rawSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
+ StreamSocketServer server = new StreamSocketServer(ref rawSocket, RawSocketServer.DefaultRawPacketHandler, serverOptions);
server.Bind(ServerEndPoint);
diff --git a/NetSharp/NetSharpExamples/Benchmarks/UdpSocketClientAsyncBenchmark.cs b/NetSharp/NetSharpExamples/Benchmarks/UdpSocketClientAsyncBenchmark.cs
@@ -61,7 +61,8 @@ namespace NetSharpExamples.Benchmarks
BenchmarkHelper benchmarkHelper = new BenchmarkHelper();
DatagramSocketClientOptions clientOptions = new DatagramSocketClientOptions((ushort)2);
- using DatagramSocketClient client = new DatagramSocketClient(AddressFamily.InterNetwork, ProtocolType.Udp, clientOptions);
+ Socket rawSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
+ using DatagramSocketClient client = new DatagramSocketClient(ref rawSocket, clientOptions);
byte[] sendBuffer = new byte[NetworkPacket.TotalSize];
byte[] receiveBuffer = new byte[NetworkPacket.TotalSize];
@@ -71,16 +72,13 @@ namespace NetSharpExamples.Benchmarks
byte[] packetBuffer = Encoding.UTF8.GetBytes($"[Client 0] Hello World! (Packet {i})");
packetBuffer.CopyTo(sendBuffer, 0);
- benchmarkHelper.StartBandwidthStopwatch();
- benchmarkHelper.StartRttStopwatch();
+ benchmarkHelper.StartStopwatch();
TransmissionResult sendResult = await client.SendAsync(in ServerEndPoint, sendBuffer);
TransmissionResult receiveResult = await client.ReceiveAsync(in ServerEndPoint, receiveBuffer);
- benchmarkHelper.StopRttStopwatch();
- benchmarkHelper.StopBandwidthStopwatch();
+ benchmarkHelper.StopStopwatch();
- benchmarkHelper.UpdateRttStats(0);
- benchmarkHelper.ResetRttStopwatch();
+ benchmarkHelper.SnapshotRttStats();
}
benchmarkHelper.PrintBandwidthStats(0, PacketCount, NetworkPacket.TotalSize);
diff --git a/NetSharp/NetSharpExamples/Benchmarks/UdpSocketClientSyncBenchmark.cs b/NetSharp/NetSharpExamples/Benchmarks/UdpSocketClientSyncBenchmark.cs
@@ -61,7 +61,8 @@ namespace NetSharpExamples.Benchmarks
BenchmarkHelper benchmarkHelper = new BenchmarkHelper();
DatagramSocketClientOptions clientOptions = new DatagramSocketClientOptions((ushort)2);
- using DatagramSocketClient client = new DatagramSocketClient(AddressFamily.InterNetwork, ProtocolType.Udp, clientOptions);
+ Socket rawSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
+ using DatagramSocketClient client = new DatagramSocketClient(ref rawSocket, clientOptions);
byte[] sendBuffer = new byte[NetworkPacket.TotalSize];
byte[] receiveBuffer = new byte[NetworkPacket.TotalSize];
@@ -73,16 +74,13 @@ namespace NetSharpExamples.Benchmarks
byte[] packetBuffer = Encoding.UTF8.GetBytes($"[Client 0] Hello World! (Packet {i})");
packetBuffer.CopyTo(sendBuffer, 0);
- benchmarkHelper.StartBandwidthStopwatch();
- benchmarkHelper.StartRttStopwatch();
+ benchmarkHelper.StartStopwatch();
TransmissionResult sendResult = client.Send(in remoteEndPoint, sendBuffer);
TransmissionResult receiveResult = client.Receive(in remoteEndPoint, receiveBuffer);
- benchmarkHelper.StopRttStopwatch();
- benchmarkHelper.StopBandwidthStopwatch();
+ benchmarkHelper.StopStopwatch();
- benchmarkHelper.UpdateRttStats(0);
- benchmarkHelper.ResetRttStopwatch();
+ benchmarkHelper.SnapshotRttStats();
}
benchmarkHelper.PrintBandwidthStats(0, PacketCount, NetworkPacket.TotalSize);
diff --git a/NetSharp/NetSharpExamples/Benchmarks/UdpSocketServerBenchmark.cs b/NetSharp/NetSharpExamples/Benchmarks/UdpSocketServerBenchmark.cs
@@ -51,16 +51,13 @@ namespace NetSharpExamples.Benchmarks
byte[] packetBuffer = Encoding.UTF8.GetBytes($"[Client {id}] Hello World! (Packet {i})");
packetBuffer.CopyTo(sendBuffer, 0);
- benchmarkHelper.StartBandwidthStopwatch();
- benchmarkHelper.StartRttStopwatch();
+ benchmarkHelper.StartStopwatch();
int sentBytes = clientSocket.SendTo(sendBuffer, remoteEndPoint);
int receivedBytes = clientSocket.ReceiveFrom(receiveBuffer, ref remoteEndPoint);
- benchmarkHelper.StopRttStopwatch();
- benchmarkHelper.StopBandwidthStopwatch();
+ benchmarkHelper.StopStopwatch();
- benchmarkHelper.UpdateRttStats(id);
- benchmarkHelper.ResetRttStopwatch();
+ benchmarkHelper.SnapshotRttStats();
}
benchmarkHelper.PrintBandwidthStats(id, PacketCount, NetworkPacket.TotalSize);
@@ -87,8 +84,8 @@ namespace NetSharpExamples.Benchmarks
DatagramSocketServerOptions serverOptions = new DatagramSocketServerOptions(clientCount, (ushort)clientCount);
- DatagramSocketServer server = new DatagramSocketServer(AddressFamily.InterNetwork, ProtocolType.Udp,
- SocketServer.DefaultPacketHandler, serverOptions);
+ Socket rawSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
+ DatagramSocketServer server = new DatagramSocketServer(ref rawSocket, RawSocketServer.DefaultRawPacketHandler, serverOptions);
server.Bind(ServerEndPoint);
@@ -112,6 +109,9 @@ namespace NetSharpExamples.Benchmarks
await serverTask;
+ rawSocket.Close();
+ rawSocket.Dispose();
+
Console.WriteLine($"UDP Server Benchmark finished!");
}
}
diff --git a/NetSharp/NetSharpExamples/Examples/TcpSocketClientExample.cs b/NetSharp/NetSharpExamples/Examples/TcpSocketClientExample.cs
@@ -20,7 +20,8 @@ namespace NetSharpExamples.Examples
{
StreamSocketClientOptions clientOptions = new StreamSocketClientOptions(2);
- using StreamSocketClient client = new StreamSocketClient(AddressFamily.InterNetwork, ProtocolType.Tcp, clientOptions);
+ Socket rawSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
+ using StreamSocketClient client = new StreamSocketClient(ref rawSocket, clientOptions);
Encoding dataEncoding = UdpSocketServerExample.ServerEncoding;
byte[] sendBuffer = new byte[NetworkPacket.TotalSize];
@@ -69,6 +70,10 @@ namespace NetSharpExamples.Examples
Console.WriteLine($"[Client] Received response with contents \'{dataEncoding.GetString(receiveBuffer).TrimEnd('\0', ' ')}\' from {remoteEndPoint}");
}
}
+
+ rawSocket.Shutdown(SocketShutdown.Both);
+ rawSocket.Close();
+ rawSocket.Dispose();
}
}
}
\ No newline at end of file
diff --git a/NetSharp/NetSharpExamples/Examples/TcpSocketServerExample.cs b/NetSharp/NetSharpExamples/Examples/TcpSocketServerExample.cs
@@ -18,18 +18,21 @@ namespace NetSharpExamples.Examples
/// <inheritdoc />
public string Name { get; } = "TCP Socket Server Example";
- public static NetworkPacket ServerPacketHandler(in NetworkPacket request, in EndPoint remoteEndPoint)
+ public static bool ServerPacketHandler(in EndPoint remoteEndPoint, ReadOnlyMemory<byte> request, Memory<byte> response)
{
// lock is not necessary, but means that console output is clean and not interleaved
lock (typeof(Console))
{
- Console.WriteLine($"[Server] Received request with contents \'{ServerEncoding.GetString(request.Data.Span).TrimEnd('\0', ' ')}\' from {remoteEndPoint}");
+ Console.WriteLine($"[Server] Received request with contents \'{ServerEncoding.GetString(request.Span).TrimEnd('\0', ' ')}\' from {remoteEndPoint}");
Console.WriteLine($"[Server] Echoing back request to {remoteEndPoint}");
}
// we echo back the request, but we could just as easily send back a new packet. if we would not want to send back any response, we need
- // to return NetworkPacket.NullPacket
- return request;
+ // to return false
+
+ request.CopyTo(response);
+
+ return true;
}
/// <inheritdoc />
@@ -38,8 +41,9 @@ namespace NetSharpExamples.Examples
StreamSocketServerOptions serverOptions =
new StreamSocketServerOptions(Environment.ProcessorCount, 2);
+ Socket rawSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
using StreamSocketServer server =
- new StreamSocketServer(AddressFamily.InterNetwork, ProtocolType.Tcp, ServerPacketHandler, serverOptions);
+ new StreamSocketServer(ref rawSocket, ServerPacketHandler, serverOptions);
server.Bind(in ServerEndPoint);
diff --git a/NetSharp/NetSharpExamples/Examples/UdpSocketClientCancellationExample.cs b/NetSharp/NetSharpExamples/Examples/UdpSocketClientCancellationExample.cs
@@ -1,101 +0,0 @@
-using NetSharp.Packets;
-using NetSharp.Sockets.Datagram;
-using NetSharp.Utils;
-
-using System;
-using System.Net;
-using System.Net.Sockets;
-using System.Threading;
-using System.Threading.Tasks;
-
-namespace NetSharpExamples.Examples
-{
- public class UdpSocketClientCancellationExample : INetSharpExample
- {
- private static readonly EndPoint ServerEndPoint = new IPEndPoint(IPAddress.Loopback, 12377);
-
- /// <inheritdoc />
- public string Name { get; } = "UDP Socket Client Cancellation Example";
-
- /// <summary>
- /// A read only server. Never sends out data!
- /// </summary>
- private Task ServerTask()
- {
- Socket server = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
-
- server.Bind(ServerEndPoint);
-
- byte[] transmissionBuffer = new byte[NetworkPacket.TotalSize];
-
- EndPoint remoteEndPoint = new IPEndPoint(IPAddress.Any, 0);
-
- 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;
- }
-
- /// <inheritdoc />
- public async Task RunAsync()
- {
- Task serverTask = Task.Factory.StartNew(ServerTask, TaskCreationOptions.LongRunning);
-
- DatagramSocketClientOptions clientOptions = new DatagramSocketClientOptions((ushort)2);
- DatagramSocketClient client = new DatagramSocketClient(AddressFamily.InterNetwork, ProtocolType.Udp, clientOptions);
-
- byte[] sendBuffer = new byte[NetworkPacket.TotalSize];
- byte[] receiveBuffer = new byte[NetworkPacket.TotalSize];
-
- EndPoint remoteEndPoint = ServerEndPoint;
-
- TimeSpan timeout = TimeSpan.FromMilliseconds(500);
-
- Console.WriteLine("Starting UDP Socket Client!");
-
- for (int i = 0; i < 10; i++)
- {
- using CancellationTokenSource sendCts = new CancellationTokenSource();
- using CancellationTokenSource receiveCts = new CancellationTokenSource();
-
- sendCts.CancelAfter(timeout);
- TransmissionResult sendResult = await client.SendAsync(remoteEndPoint, sendBuffer, SocketFlags.None, sendCts.Token);
-
- if (sendResult.TimedOut())
- {
- Console.WriteLine("Send timed out!");
- }
- else
- {
- Console.WriteLine($"Sent {sendResult.Count} bytes of data!");
-
- receiveCts.CancelAfter(timeout);
- TransmissionResult receiveResult = await client.ReceiveAsync(remoteEndPoint, receiveBuffer, SocketFlags.None, receiveCts.Token);
-
- if (receiveResult.TimedOut())
- {
- Console.WriteLine("Receive timed out!");
- }
- else
- {
- 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/Examples/UdpSocketClientExample.cs b/NetSharp/NetSharpExamples/Examples/UdpSocketClientExample.cs
@@ -20,7 +20,8 @@ namespace NetSharpExamples.Examples
{
DatagramSocketClientOptions clientOptions = new DatagramSocketClientOptions(2);
- using DatagramSocketClient client = new DatagramSocketClient(AddressFamily.InterNetwork, ProtocolType.Udp, clientOptions);
+ Socket rawSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
+ using DatagramSocketClient client = new DatagramSocketClient(ref rawSocket, clientOptions);
Encoding dataEncoding = UdpSocketServerExample.ServerEncoding;
byte[] sendBuffer = new byte[NetworkPacket.TotalSize];
@@ -39,7 +40,7 @@ namespace NetSharpExamples.Examples
/* a cancellable asynchronous version also exists. use only when necessary due to the inherent performance penalty of async operations
TransmissionResult sendResult =
- await client.SendAsync(in remoteEndPoint, sendBuffer, SocketFlags.None, CancellationToken.None);
+ await client.SendAsync(in remoteEndPoint, sendBuffer, SocketFlags.None);
*/
// lock is not necessary, but means that console output is clean and not interleaved
@@ -53,7 +54,7 @@ namespace NetSharpExamples.Examples
/* a cancellable asynchronous version also exists. use only when necessary due to the inherent performance penalty of async operations
TransmissionResult receiveResult =
- await client.ReceiveAsync(in remoteEndPoint, receiveBuffer, SocketFlags.None, CancellationToken.None);
+ await client.ReceiveAsync(in remoteEndPoint, receiveBuffer, SocketFlags.None);
*/
// lock is not necessary, but means that console output is clean and not interleaved
@@ -62,6 +63,9 @@ namespace NetSharpExamples.Examples
Console.WriteLine($"[Client] Received response with contents \'{dataEncoding.GetString(receiveBuffer).TrimEnd('\0', ' ')}\' from {remoteEndPoint}");
}
}
+
+ rawSocket.Close();
+ rawSocket.Dispose();
}
}
}
\ No newline at end of file
diff --git a/NetSharp/NetSharpExamples/Examples/UdpSocketServerExample.cs b/NetSharp/NetSharpExamples/Examples/UdpSocketServerExample.cs
@@ -18,18 +18,21 @@ namespace NetSharpExamples.Examples
/// <inheritdoc />
public string Name { get; } = "UDP Socket Server Example";
- public static NetworkPacket ServerPacketHandler(in NetworkPacket request, in EndPoint remoteEndPoint)
+ public static bool ServerPacketHandler(in EndPoint remoteEndPoint, ReadOnlyMemory<byte> request, Memory<byte> response)
{
// lock is not necessary, but means that console output is clean and not interleaved
lock (typeof(Console))
{
- Console.WriteLine($"[Server] Received request with contents \'{ServerEncoding.GetString(request.Data.Span).TrimEnd('\0', ' ')}\' from {remoteEndPoint}");
+ Console.WriteLine($"[Server] Received request with contents \'{ServerEncoding.GetString(request.Span).TrimEnd('\0', ' ')}\' from {remoteEndPoint}");
Console.WriteLine($"[Server] Echoing back request to {remoteEndPoint}");
}
// we echo back the request, but we could just as easily send back a new packet. if we would not want to send back any response, we need
- // to return NetworkPacket.NullPacket
- return request;
+ // to return false
+
+ request.CopyTo(response);
+
+ return true;
}
/// <inheritdoc />
@@ -38,8 +41,9 @@ namespace NetSharpExamples.Examples
DatagramSocketServerOptions serverOptions =
new DatagramSocketServerOptions(Environment.ProcessorCount, 2);
+ Socket rawSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
using DatagramSocketServer server =
- new DatagramSocketServer(AddressFamily.InterNetwork, ProtocolType.Udp, ServerPacketHandler, serverOptions);
+ new DatagramSocketServer(ref rawSocket, ServerPacketHandler, serverOptions);
server.Bind(in ServerEndPoint);
diff --git a/NetSharp/NetSharpExamples/NetSharpExamples.xml b/NetSharp/NetSharpExamples/NetSharpExamples.xml
@@ -4,6 +4,12 @@
<name>NetSharpExamples</name>
</assembly>
<members>
+ <member name="P:NetSharpExamples.Benchmarks.DatagramNetworkReaderBenchmark.Name">
+ <inheritdoc />
+ </member>
+ <member name="M:NetSharpExamples.Benchmarks.DatagramNetworkReaderBenchmark.RunAsync">
+ <inheritdoc />
+ </member>
<member name="F:NetSharpExamples.Benchmarks.TcpSocketClientAsyncBenchmark.PacketCount">
<summary>
Packets contain 8 KiB of data, so 1 000 000 packet = 8GiB. the more data the more accurate the benchmark, but the slower it will run.
@@ -82,17 +88,6 @@
<member name="M:NetSharpExamples.Examples.TcpSocketServerExample.RunAsync">
<inheritdoc />
</member>
- <member name="P:NetSharpExamples.Examples.UdpSocketClientCancellationExample.Name">
- <inheritdoc />
- </member>
- <member name="M:NetSharpExamples.Examples.UdpSocketClientCancellationExample.ServerTask">
- <summary>
- A read only server. Never sends out data!
- </summary>
- </member>
- <member name="M:NetSharpExamples.Examples.UdpSocketClientCancellationExample.RunAsync">
- <inheritdoc />
- </member>
<member name="P:NetSharpExamples.Examples.UdpSocketClientExample.Name">
<inheritdoc />
</member>
diff --git a/NetSharp/NetSharpExamples/Program.cs b/NetSharp/NetSharpExamples/Program.cs
@@ -16,7 +16,6 @@ namespace NetSharpExamples
new UdpSocketClientSyncBenchmark(),
new UdpSocketClientAsyncBenchmark(),
new UdpSocketClientExample(),
- new UdpSocketClientCancellationExample(), // TODO make functional
// TCP socket server and client examples
new TcpSocketServerBenchmark(),
@@ -24,6 +23,9 @@ namespace NetSharpExamples
new TcpSocketClientSyncBenchmark(),
new TcpSocketClientAsyncBenchmark(),
new TcpSocketClientExample(),
+
+ // Restructured UDP server and client benchmarks
+ new DatagramNetworkReaderBenchmark(),
};
private static async Task Main()