commit f30b7d469c349902f22371419655e350df558bd5
parent 502cd5d5e0d41a210e5ca4405b14ee05cc6ecbc7
Author: Mikolaj Lenczewski <mikolaj.lenczewski308@gmail.com>
Date: Thu, 23 Apr 2020 18:23:22 +0100
Made network packets not throw exceptions. Playing around with doc comment settings.
Diffstat:
17 files changed, 828 insertions(+), 517 deletions(-)
diff --git a/NetSharp/NetSharp/Packets/NetworkPacket.cs b/NetSharp/NetSharp/Packets/NetworkPacket.cs
@@ -1,49 +1,96 @@
using System;
+using System.Runtime.CompilerServices;
namespace NetSharp.Packets
{
- //TODO document
+ /// <summary>
+ /// Represents a raw packet sent across the network.
+ /// </summary>
public readonly struct NetworkPacket
{
+ /// <summary>
+ /// The size in bytes of the packet data segment.
+ /// </summary>
public const int DataSize = 8192;
+ /// <summary>
+ /// The size in bytes of the packet footer segment.
+ /// </summary>
public const int FooterSize = NetworkPacketFooter.TotalSize;
+ /// <summary>
+ /// The size in bytes of the packet header segment.
+ /// </summary>
public const int HeaderSize = NetworkPacketHeader.TotalSize;
+ /// <summary>
+ /// The total size of the packet in bytes.
+ /// </summary>
public const int TotalSize = HeaderSize + DataSize + FooterSize;
+ /// <summary>
+ /// Represents an empty packet.
+ /// </summary>
public static NetworkPacket NullPacket = new NetworkPacket();
+ /// <summary>
+ /// The data held by this packet instance.
+ /// </summary>
public readonly ReadOnlyMemory<byte> Data;
+ /// <summary>
+ /// The footer for this packet instance, holding additional metadata.
+ /// </summary>
public readonly NetworkPacketFooter Footer;
+ /// <summary>
+ /// The header for this packet instance, holding additional metadata.
+ /// </summary>
public readonly NetworkPacketHeader Header;
/// <summary>
/// Constructs a new instance of the <see cref="NetworkPacket" /> struct.
/// </summary>
- /// <param name="packetHeader">The header for this packet.</param>
- /// <param name="packetDataBuffer">The data that should be stored in the packet.</param>
- /// <param name="packetFooter">The footer for this packet.</param>
- /// <exception cref="ArgumentException">
- /// Thrown when the given <paramref name="packetDataBuffer" /> exceeds <see cref="TotalSize" /> bytes in size.
- /// </exception>
+ /// <param name="packetHeader">
+ /// The header for this packet.
+ /// </param>
+ /// <param name="packetDataBuffer">
+ /// The data that should be stored in the packet.
+ /// </param>
+ /// <param name="packetFooter">
+ /// The footer for this packet.
+ /// </param>
private NetworkPacket(NetworkPacketHeader packetHeader, ReadOnlyMemory<byte> packetDataBuffer, NetworkPacketFooter packetFooter)
{
- if (packetDataBuffer.Length > DataSize)
- {
- throw new ArgumentException(
- $"Given buffer exceeds {TotalSize} bytes, and cannot fit into a network packet",
- nameof(packetDataBuffer));
- }
+ Header = packetHeader;
Data = packetDataBuffer;
+
+ Footer = packetFooter;
}
- public static NetworkPacket Deserialise(ReadOnlyMemory<byte> buffer)
+ /// <summary>
+ /// Deserialises the serialised packet in the given memory buffer into a new <see cref="NetworkPacket" /> instance.
+ /// </summary>
+ /// <param name="buffer">
+ /// The memory buffer to read the serialised packet instance from.
+ /// </param>
+ /// <param name="instance">
+ /// The deserialised instance.
+ /// </param>
+ /// <returns>
+ /// Whether the deserialisation attempt was successful. The <paramref name="instance" /> will be equal to <see cref="NullPacket" /> if the
+ /// attempt fails.
+ /// </returns>
+ public static bool Deserialise(ReadOnlyMemory<byte> buffer, out NetworkPacket instance)
{
+ if (buffer.Length != TotalSize)
+ {
+ instance = NullPacket;
+
+ return false;
+ }
+
ReadOnlyMemory<byte> serialisedPacketHeader = buffer.Slice(0, HeaderSize);
NetworkPacketHeader packetHeader = NetworkPacketHeader.Deserialise(serialisedPacketHeader);
@@ -52,11 +99,30 @@ namespace NetSharp.Packets
ReadOnlyMemory<byte> serialisedPacketFooter = buffer.Slice(HeaderSize + DataSize, FooterSize);
NetworkPacketFooter packetFooter = NetworkPacketFooter.Deserialise(serialisedPacketFooter);
- return new NetworkPacket(packetHeader, packetDataBuffer, packetFooter);
+ instance = new NetworkPacket(packetHeader, packetDataBuffer, packetFooter);
+
+ return true;
}
- public static void Serialise(NetworkPacket instance, Memory<byte> buffer)
+ /// <summary>
+ /// Serialises the given <see cref="NetworkPacket" /> instance into the given memory buffer.
+ /// </summary>
+ /// <param name="instance">
+ /// The packet instance which should be serialised.
+ /// </param>
+ /// <param name="buffer">
+ /// The memory buffer to write the serialised packet instance to. <see cref="TotalSize" /> bytes will be written into this buffer on success.
+ /// </param>
+ /// <returns>
+ /// Whether the serialisation attempt was successful. No bytes are written to the <paramref name="buffer" /> if the attempt fails.
+ /// </returns>
+ public static bool Serialise(NetworkPacket instance, Memory<byte> buffer)
{
+ if (buffer.Length < TotalSize)
+ {
+ return false;
+ }
+
Memory<byte> packetHeader = buffer.Slice(0, HeaderSize);
NetworkPacketHeader.Serialise(instance.Header, packetHeader);
@@ -65,35 +131,87 @@ namespace NetSharp.Packets
Memory<byte> packetFooter = buffer.Slice(HeaderSize + DataSize, FooterSize);
NetworkPacketFooter.Serialise(instance.Footer, packetFooter);
+
+ return true;
}
}
- //TODO document
+ /// <summary>
+ /// Represents the footer of a <see cref="NetworkPacket" />, holding additional metadata.
+ /// </summary>
public readonly struct NetworkPacketFooter
{
+ /// <summary>
+ /// The total size of the packet footer, in bytes.
+ /// </summary>
public const int TotalSize = 0;
- public static NetworkPacketFooter Deserialise(ReadOnlyMemory<byte> buffer)
+ /// <summary>
+ /// Deserialises the serialised packet footer in the given memory buffer into a new <see cref="NetworkPacketFooter" /> instance.
+ /// </summary>
+ /// <param name="buffer">
+ /// The memory buffer to read the serialised packet footer instance from.
+ /// </param>
+ /// <returns>
+ /// The deserialised instance.
+ /// </returns>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal static NetworkPacketFooter Deserialise(ReadOnlyMemory<byte> buffer)
{
return new NetworkPacketFooter();
}
- public static void Serialise(NetworkPacketFooter instance, Memory<byte> buffer)
+ /// <summary>
+ /// Serialises the given <see cref="NetworkPacketFooter" /> instance into the given memory buffer.
+ /// </summary>
+ /// <param name="instance">
+ /// The packet footer instance which should be serialised.
+ /// </param>
+ /// <param name="buffer">
+ /// The memory buffer to write the serialised packet footer instance to.
+ /// </param>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal static void Serialise(NetworkPacketFooter instance, Memory<byte> buffer)
{
}
}
- //TODO document
+ /// <summary>
+ /// Represents the header of a <see cref="NetworkPacket" />, holding additional metadata.
+ /// </summary>
public readonly struct NetworkPacketHeader
{
+ /// <summary>
+ /// The total size of the packet header, in bytes.
+ /// </summary>
public const int TotalSize = 0;
- public static NetworkPacketHeader Deserialise(ReadOnlyMemory<byte> buffer)
+ /// <summary>
+ /// Deserialises the serialised packet header in the given memory buffer into a new <see cref="NetworkPacketHeader" /> instance.
+ /// </summary>
+ /// <param name="buffer">
+ /// The memory buffer to read the serialised packet header instance from.
+ /// </param>
+ /// <returns>
+ /// The deserialised instance.
+ /// </returns>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal static NetworkPacketHeader Deserialise(ReadOnlyMemory<byte> buffer)
{
return new NetworkPacketHeader();
}
- public static void Serialise(NetworkPacketHeader instance, Memory<byte> buffer)
+ /// <summary>
+ /// Serialises the given <see cref="NetworkPacketHeader" /> instance into the given memory buffer.
+ /// </summary>
+ /// <param name="instance">
+ /// The packet header instance which should be serialised.
+ /// </param>
+ /// <param name="buffer">
+ /// The memory buffer to write the serialised packet header instance to.
+ /// </param>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal static void Serialise(NetworkPacketHeader instance, Memory<byte> buffer)
{
}
}
diff --git a/NetSharp/NetSharp/Sockets/Datagram/DatagramSocketClient.cs b/NetSharp/NetSharp/Sockets/Datagram/DatagramSocketClient.cs
@@ -13,16 +13,12 @@ namespace NetSharp.Sockets.Datagram
public readonly struct DatagramSocketClientOptions
{
public static readonly DatagramSocketClientOptions Defaults =
- new DatagramSocketClientOptions(NetworkPacket.TotalSize, 0);
-
- public readonly int PacketSize;
+ new DatagramSocketClientOptions(0);
public readonly ushort PreallocatedTransmissionArgs;
- public DatagramSocketClientOptions(int packetSize, ushort preallocatedTransmissionArgs)
+ public DatagramSocketClientOptions(ushort preallocatedTransmissionArgs)
{
- PacketSize = packetSize;
-
PreallocatedTransmissionArgs = preallocatedTransmissionArgs;
}
}
@@ -34,9 +30,8 @@ namespace NetSharp.Sockets.Datagram
private readonly DatagramSocketClientOptions clientOptions;
public DatagramSocketClient(in AddressFamily connectionAddressFamily, in ProtocolType connectionProtocolType,
- in DatagramSocketClientOptions? clientOptions = null) : base(in connectionAddressFamily, SocketType.Dgram,
- in connectionProtocolType, clientOptions?.PacketSize ?? DatagramSocketClientOptions.Defaults.PacketSize,
- clientOptions?.PreallocatedTransmissionArgs ?? DatagramSocketClientOptions.Defaults.PreallocatedTransmissionArgs)
+ in DatagramSocketClientOptions? clientOptions = null) : base(in connectionAddressFamily, SocketType.Dgram, in connectionProtocolType,
+ NetworkPacket.TotalSize, clientOptions?.PreallocatedTransmissionArgs ?? DatagramSocketClientOptions.Defaults.PreallocatedTransmissionArgs)
{
this.clientOptions = clientOptions ?? DatagramSocketClientOptions.Defaults;
}
@@ -46,6 +41,70 @@ namespace NetSharp.Sockets.Datagram
get { return ref clientOptions; }
}
+ private void CompleteConnect(SocketAsyncEventArgs args)
+ {
+ AsyncOperationToken connectToken = (AsyncOperationToken)args.UserToken;
+
+ if (connectToken.CancellationToken.IsCancellationRequested)
+ {
+ connectToken.CompletionSource.SetCanceled();
+ }
+ else if (args.SocketError == SocketError.Success)
+ {
+ connectToken.CompletionSource.SetResult(true);
+ }
+ else
+ {
+ connectToken.CompletionSource.SetException(new SocketException((int)args.SocketError));
+ }
+
+ TransmissionArgsPool.Return(args);
+ }
+
+ private void CompleteReceiveFrom(SocketAsyncEventArgs args)
+ {
+ AsyncTransmissionToken receiveToken = (AsyncTransmissionToken)args.UserToken;
+
+ if (receiveToken.CancellationToken.IsCancellationRequested)
+ {
+ receiveToken.CompletionSource.SetCanceled();
+ }
+ else if (args.SocketError == SocketError.Success)
+ {
+ TransmissionResult result = new TransmissionResult(in args);
+
+ receiveToken.CompletionSource.SetResult(result);
+ }
+ else
+ {
+ receiveToken.CompletionSource.SetException(new SocketException((int)args.SocketError));
+ }
+
+ TransmissionArgsPool.Return(args);
+ }
+
+ private void CompleteSendTo(SocketAsyncEventArgs args)
+ {
+ AsyncTransmissionToken sendToken = (AsyncTransmissionToken)args.UserToken;
+
+ if (sendToken.CancellationToken.IsCancellationRequested)
+ {
+ sendToken.CompletionSource.SetCanceled();
+ }
+ else if (args.SocketError == SocketError.Success)
+ {
+ TransmissionResult result = new TransmissionResult(in args);
+
+ sendToken.CompletionSource.SetResult(result);
+ }
+ else
+ {
+ sendToken.CompletionSource.SetException(new SocketException((int)args.SocketError));
+ }
+
+ TransmissionArgsPool.Return(args);
+ }
+
/// <inheritdoc />
protected override bool CanTransmissionArgsBeReused(in SocketAsyncEventArgs args)
{
@@ -76,66 +135,17 @@ namespace NetSharp.Sockets.Datagram
switch (args.LastOperation)
{
case SocketAsyncOperation.Connect:
- AsyncOperationToken connectToken = (AsyncOperationToken)args.UserToken;
-
- if (connectToken.CancellationToken.IsCancellationRequested)
- {
- connectToken.CompletionSource.SetCanceled();
- }
- else if (args.SocketError == SocketError.Success)
- {
- connectToken.CompletionSource.SetResult(true);
- }
- else
- {
- connectToken.CompletionSource.SetException(new SocketException((int)args.SocketError));
- }
-
- TransmissionArgsPool.Return(args);
+ CompleteConnect(args);
break;
case SocketAsyncOperation.ReceiveFrom:
- AsyncTransmissionToken receiveToken = (AsyncTransmissionToken)args.UserToken;
-
- if (receiveToken.CancellationToken.IsCancellationRequested)
- {
- receiveToken.CompletionSource.SetCanceled();
- }
- else if (args.SocketError == SocketError.Success)
- {
- TransmissionResult result = new TransmissionResult(in args);
-
- receiveToken.CompletionSource.SetResult(result);
- }
- else
- {
- receiveToken.CompletionSource.SetException(new SocketException((int)args.SocketError));
- }
-
- TransmissionArgsPool.Return(args);
+ CompleteReceiveFrom(args);
break;
case SocketAsyncOperation.SendTo:
- AsyncTransmissionToken sendToken = (AsyncTransmissionToken)args.UserToken;
-
- if (sendToken.CancellationToken.IsCancellationRequested)
- {
- sendToken.CompletionSource.SetCanceled();
- }
- else if (args.SocketError == SocketError.Success)
- {
- TransmissionResult result = new TransmissionResult(in args);
-
- sendToken.CompletionSource.SetResult(result);
- }
- else
- {
- sendToken.CompletionSource.SetException(new SocketException((int)args.SocketError));
- }
-
- TransmissionArgsPool.Return(args);
+ CompleteSendTo(args);
break;
diff --git a/NetSharp/NetSharp/Sockets/Datagram/DatagramSocketServer.cs b/NetSharp/NetSharp/Sockets/Datagram/DatagramSocketServer.cs
@@ -12,16 +12,13 @@ namespace NetSharp.Sockets.Datagram
public readonly struct DatagramSocketServerOptions
{
public static readonly DatagramSocketServerOptions Defaults =
- new DatagramSocketServerOptions(NetworkPacket.TotalSize, Environment.ProcessorCount, 0);
+ new DatagramSocketServerOptions(Environment.ProcessorCount, 0);
public readonly int ConcurrentReceiveFromCalls;
- public readonly int PacketSize;
public readonly ushort PreallocatedTransmissionArgs;
- public DatagramSocketServerOptions(int packetSize, int concurrentReceiveFromCalls, ushort preallocatedTransmissionArgs)
+ public DatagramSocketServerOptions(int concurrentReceiveFromCalls, ushort preallocatedTransmissionArgs)
{
- PacketSize = packetSize;
-
ConcurrentReceiveFromCalls = concurrentReceiveFromCalls;
PreallocatedTransmissionArgs = preallocatedTransmissionArgs;
@@ -41,13 +38,14 @@ namespace NetSharp.Sockets.Datagram
/// <summary>
/// Constructs a new instance of the <see cref="DatagramSocketServer" /> class.
/// </summary>
- /// <param name="serverOptions">Additional options to configure the server.</param>
+ /// <param name="serverOptions">
+ /// 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,
- serverOptions?.PacketSize ?? DatagramSocketServerOptions.Defaults.PacketSize,
- serverOptions?.PreallocatedTransmissionArgs ?? DatagramSocketServerOptions.Defaults.PreallocatedTransmissionArgs)
+ NetworkPacket.TotalSize, serverOptions?.PreallocatedTransmissionArgs ?? DatagramSocketServerOptions.Defaults.PreallocatedTransmissionArgs)
{
this.serverOptions = serverOptions ?? DatagramSocketServerOptions.Defaults;
}
@@ -63,13 +61,13 @@ namespace NetSharp.Sockets.Datagram
if (receiveArgs.SocketError == SocketError.Success)
{
- NetworkPacket request = NetworkPacket.Deserialise(receiveArgs.MemoryBuffer);
+ NetworkPacket.Deserialise(receiveArgs.MemoryBuffer, out NetworkPacket request);
NetworkPacket response = PacketHandler(in request, receiveArgs.RemoteEndPoint);
if (!response.Equals(NetworkPacket.NullPacket))
{
- byte[] sendBuffer = BufferPool.Rent(ServerOptions.PacketSize);
+ byte[] sendBuffer = BufferPool.Rent(NetworkPacket.TotalSize);
Memory<byte> sendBufferMemory = new Memory<byte>(sendBuffer);
NetworkPacket.Serialise(response, sendBufferMemory);
@@ -108,7 +106,7 @@ namespace NetSharp.Sockets.Datagram
return;
}
- byte[] receiveBuffer = BufferPool.Rent(ServerOptions.PacketSize);
+ byte[] receiveBuffer = BufferPool.Rent(NetworkPacket.TotalSize);
Memory<byte> receiveBufferMemory = new Memory<byte>(receiveBuffer);
receiveArgs.SetBuffer(receiveBufferMemory);
@@ -183,10 +181,12 @@ namespace NetSharp.Sockets.Datagram
ReceiveFrom(newReceiveArgs); // start a new receive from operation immediately, to not drop any packets
CompleteReceiveFrom(args);
+
break;
case SocketAsyncOperation.SendTo:
CompleteSendTo(args);
+
break;
default:
diff --git a/NetSharp/NetSharp/Sockets/SocketClient.cs b/NetSharp/NetSharp/Sockets/SocketClient.cs
@@ -15,24 +15,34 @@ namespace NetSharp.Sockets
/// <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="maxPooledBufferLength">The maximum length of a pooled network IO buffer.</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 maxPooledBufferLength, in ushort preallocatedTransmissionArgs)
- : base(in connectionAddressFamily, in connectionSocketType, in connectionProtocolType, in maxPooledBufferLength,
- in preallocatedTransmissionArgs)
+ /// <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>
/// 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" />).
+ /// 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="remoteEndPoint">
+ /// The remote end point which to which to connect the client.
+ /// </param>
public void Connect(in EndPoint remoteEndPoint)
{
Connection.Connect(remoteEndPoint);
@@ -40,12 +50,17 @@ namespace NetSharp.Sockets
/// <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" />).
+ /// 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 <see cref="CancellationToken" /> upon whose cancellation the connection attempt should be aborted.</param>
- /// <returns>A <see cref="ValueTask" /> representing the connection attempt.</returns>
+ /// <param name="remoteEndPoint">
+ /// The remote end point which to which to connect the client.
+ /// </param>
+ /// <param name="cancellationToken">
+ /// The <see cref="CancellationToken" /> upon whose cancellation the connection attempt should be aborted.
+ /// </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>();
@@ -101,10 +116,18 @@ namespace NetSharp.Sockets
/// <summary>
/// Constructs a new instance of the <see cref="AsyncOperationCancellationToken" /> struct.
/// </summary>
- /// <param name="socket">The socket on which the operation was started.</param>
- /// <param name="args">The socket event args associated with the operation.</param>
- /// <param name="argsPool">The pool to which the <paramref name="args" /> instance will be returned upon cancellation.</param>
- /// <param name="completionSource">The completion source associated with the operation.</param>
+ /// <param name="socket">
+ /// The socket on which the operation was started.
+ /// </param>
+ /// <param name="args">
+ /// The socket event args associated with the operation.
+ /// </param>
+ /// <param name="argsPool">
+ /// The pool to which the <paramref name="args" /> instance will be returned upon cancellation.
+ /// </param>
+ /// <param name="completionSource">
+ /// The completion source associated with the operation.
+ /// </param>
public AsyncOperationCancellationToken(in Socket socket, in SocketAsyncEventArgs args,
in SlimObjectPool<SocketAsyncEventArgs> argsPool, in TaskCompletionSource<bool> completionSource)
{
@@ -136,8 +159,12 @@ namespace NetSharp.Sockets
/// <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>
+ /// <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;
@@ -174,10 +201,18 @@ namespace NetSharp.Sockets
/// <summary>
/// Constructs a new instance of the <see cref="AsyncTransmissionCancellationToken" /> struct.
/// </summary>
- /// <param name="socket">The socket on which the operation was started.</param>
- /// <param name="args">The socket event args associated with the operation.</param>
- /// <param name="argsPool">The pool to which the <paramref name="args" /> instance will be returned upon cancellation.</param>
- /// <param name="completionSource">The completion source associated with the operation.</param>
+ /// <param name="socket">
+ /// The socket on which the operation was started.
+ /// </param>
+ /// <param name="args">
+ /// The socket event args associated with the operation.
+ /// </param>
+ /// <param name="argsPool">
+ /// The pool to which the <paramref name="args" /> instance will be returned upon cancellation.
+ /// </param>
+ /// <param name="completionSource">
+ /// The completion source associated with the operation.
+ /// </param>
public AsyncTransmissionCancellationToken(in Socket socket, in SocketAsyncEventArgs args,
in SlimObjectPool<SocketAsyncEventArgs> argsPool, in TaskCompletionSource<TransmissionResult> completionSource)
{
@@ -209,8 +244,12 @@ namespace NetSharp.Sockets
/// <summary>
/// Constructs a new instance of the <see cref="AsyncTransmissionToken" /> 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>
+ /// <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 AsyncTransmissionToken(in TaskCompletionSource<TransmissionResult> completionSource, in CancellationToken cancellationToken)
{
CompletionSource = completionSource;
diff --git a/NetSharp/NetSharp/Sockets/SocketConnection.cs b/NetSharp/NetSharp/Sockets/SocketConnection.cs
@@ -19,8 +19,8 @@ namespace NetSharp.Sockets
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.
+ /// 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;
@@ -32,17 +32,27 @@ namespace NetSharp.Sockets
/// <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="maxPooledBufferLength">The maximum size of the buffers stored in the <see cref="BufferPool" />.</param>
- /// <param name="preallocatedTransmissionArgs">The number of <see cref="SocketAsyncEventArgs" /> objects to initially preallocate.</param>
+ /// <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 maxPooledBufferLength, in ushort preallocatedTransmissionArgs)
+ in ProtocolType connectionProtocolType, in int pooledBufferMaxSize, in ushort preallocatedTransmissionArgs)
{
Connection = new Socket(connectionAddressFamily, connectionSocketType, connectionProtocolType);
- BufferPool = ArrayPool<byte>.Create(maxPooledBufferLength, 1000);
+ BufferPool = ArrayPool<byte>.Create(pooledBufferMaxSize, 1000);
TransmissionArgsPool = new SlimObjectPool<SocketAsyncEventArgs>(CreateTransmissionArgs,
ResetTransmissionArgs, DestroyTransmissionArgs, CanTransmissionArgsBeReused);
@@ -65,34 +75,44 @@ namespace NetSharp.Sockets
}
/// <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.
+ /// 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>
+ /// <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.
+ /// 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>
+ /// <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.
+ /// 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>
+ /// <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>
+ /// <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;
@@ -104,14 +124,20 @@ namespace NetSharp.Sockets
/// <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>
+ /// <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>
+ /// <param name="args">
+ /// The <see cref="SocketAsyncEventArgs" /> instance that should be reset.
+ /// </param>
protected abstract void ResetTransmissionArgs(SocketAsyncEventArgs args);
/// <inheritdoc cref="Socket.SetSocketOption(SocketOptionLevel,SocketOptionName,bool)" />
@@ -141,7 +167,9 @@ namespace NetSharp.Sockets
/// <summary>
/// Binds the underlying socket.
/// </summary>
- /// <param name="localEndPoint">The end point to which the socket should be bound.</param>
+ /// <param name="localEndPoint">
+ /// The end point to which the socket should be bound.
+ /// </param>
public void Bind(in EndPoint localEndPoint)
{
Connection.Bind(localEndPoint);
@@ -175,7 +203,9 @@ namespace NetSharp.Sockets
/// <summary>
/// Shuts down the underlying socket.
/// </summary>
- /// <param name="how">Which socket transmission functions should be shut down on the socket.</param>
+ /// <param name="how">
+ /// Which socket transmission functions should be shut down on the socket.
+ /// </param>
public void Shutdown(SocketShutdown how)
{
try
diff --git a/NetSharp/NetSharp/Sockets/SocketServer.cs b/NetSharp/NetSharp/Sockets/SocketServer.cs
@@ -10,11 +10,14 @@ 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>
+ /// <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" />.
+ /// 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);
@@ -31,16 +34,27 @@ namespace NetSharp.Sockets
/// <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="maxPooledBufferLength">The maximum length of a pooled network IO buffer.</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 maxPooledBufferLength,
- in ushort preallocatedTransmissionArgs) : base(in connectionAddressFamily, in connectionSocketType,
- in connectionProtocolType, in maxPooledBufferLength, preallocatedTransmissionArgs)
+ /// <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;
}
@@ -48,9 +62,15 @@ namespace NetSharp.Sockets
/// <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>
+ /// <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;
@@ -59,8 +79,12 @@ namespace NetSharp.Sockets
/// <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>
+ /// <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
@@ -12,16 +12,12 @@ namespace NetSharp.Sockets.Stream
public readonly struct StreamSocketClientOptions
{
public static readonly StreamSocketClientOptions Defaults =
- new StreamSocketClientOptions(NetworkPacket.TotalSize, 0);
-
- public readonly int PacketSize;
+ new StreamSocketClientOptions(0);
public readonly ushort PreallocatedTransmissionArgs;
- public StreamSocketClientOptions(int packetSize, ushort preallocatedTransmissionArgs)
+ public StreamSocketClientOptions(ushort preallocatedTransmissionArgs)
{
- PacketSize = packetSize;
-
PreallocatedTransmissionArgs = preallocatedTransmissionArgs;
}
}
@@ -33,9 +29,8 @@ namespace NetSharp.Sockets.Stream
private readonly StreamSocketClientOptions clientOptions;
public StreamSocketClient(in AddressFamily connectionAddressFamily, in ProtocolType connectionProtocolType,
- in StreamSocketClientOptions? clientOptions = null) : base(in connectionAddressFamily, SocketType.Stream,
- in connectionProtocolType, clientOptions?.PacketSize ?? StreamSocketClientOptions.Defaults.PacketSize,
- clientOptions?.PreallocatedTransmissionArgs ?? StreamSocketClientOptions.Defaults.PreallocatedTransmissionArgs)
+ in StreamSocketClientOptions? clientOptions = null) : base(in connectionAddressFamily, SocketType.Stream, in connectionProtocolType,
+ NetworkPacket.TotalSize, clientOptions?.PreallocatedTransmissionArgs ?? StreamSocketClientOptions.Defaults.PreallocatedTransmissionArgs)
{
this.clientOptions = clientOptions ?? StreamSocketClientOptions.Defaults;
}
@@ -45,178 +40,198 @@ namespace NetSharp.Sockets.Stream
get { return ref clientOptions; }
}
- /// <inheritdoc />
- protected override bool CanTransmissionArgsBeReused(in SocketAsyncEventArgs args)
+ private void CompleteConnect(SocketAsyncEventArgs args)
{
- return true;
- }
+ AsyncOperationToken connectToken = (AsyncOperationToken)args.UserToken;
- /// <inheritdoc />
- protected override SocketAsyncEventArgs CreateTransmissionArgs()
- {
- SocketAsyncEventArgs connectionArgs = new SocketAsyncEventArgs();
+ if (connectToken.CancellationToken.IsCancellationRequested)
+ {
+ Connection.Disconnect(true);
- connectionArgs.Completed += HandleIoCompleted;
+ connectToken.CompletionSource.SetCanceled();
+ }
+ else if (args.SocketError == SocketError.Success)
+ {
+ connectToken.CompletionSource.SetResult(true);
+ }
+ else
+ {
+ connectToken.CompletionSource.SetException(new SocketException((int)args.SocketError));
+ }
- return connectionArgs;
+ TransmissionArgsPool.Return(args);
}
- /// <inheritdoc />
- protected override void DestroyTransmissionArgs(SocketAsyncEventArgs remoteConnectionArgs)
+ private void CompleteDisconnect(SocketAsyncEventArgs args)
{
- remoteConnectionArgs.Completed -= HandleIoCompleted;
+ AsyncOperationToken disconnectToken = (AsyncOperationToken)args.UserToken;
- remoteConnectionArgs.Dispose();
+ if (disconnectToken.CancellationToken.IsCancellationRequested)
+ {
+ disconnectToken.CompletionSource.SetCanceled();
+ }
+ else if (args.SocketError == SocketError.Success)
+ {
+ disconnectToken.CompletionSource.SetResult(true);
+ }
+ else
+ {
+ disconnectToken.CompletionSource.SetException(new SocketException((int)args.SocketError));
+ }
+
+ TransmissionArgsPool.Return(args);
}
- /// <inheritdoc />
- protected override void HandleIoCompleted(object sender, SocketAsyncEventArgs args)
+ private void CompleteReceive(SocketAsyncEventArgs args)
{
- switch (args.LastOperation)
+ AsyncTransmissionToken receiveToken = (AsyncTransmissionToken)args.UserToken;
+
+ if (receiveToken.CancellationToken.IsCancellationRequested)
{
- case SocketAsyncOperation.Connect:
- AsyncOperationToken connectToken = (AsyncOperationToken)args.UserToken;
-
- if (connectToken.CancellationToken.IsCancellationRequested)
- {
- Connection.Disconnect(true);
-
- connectToken.CompletionSource.SetCanceled();
- }
- else if (args.SocketError == SocketError.Success)
- {
- connectToken.CompletionSource.SetResult(true);
- }
- else
- {
- connectToken.CompletionSource.SetException(new SocketException((int)args.SocketError));
- }
+ receiveToken.CompletionSource.SetCanceled();
- TransmissionArgsPool.Return(args);
+ TransmissionArgsPool.Return(args);
+ }
+ else if (args.SocketError == SocketError.Success)
+ {
+ Memory<byte> transmissionBuffer = args.MemoryBuffer;
+ int expectedBytes = transmissionBuffer.Length;
- break;
+ if (args.BytesTransferred == expectedBytes)
+ {
+ // buffer was fully received
- case SocketAsyncOperation.Disconnect:
- AsyncOperationToken disconnectToken = (AsyncOperationToken)args.UserToken;
-
- if (disconnectToken.CancellationToken.IsCancellationRequested)
- {
- disconnectToken.CompletionSource.SetCanceled();
- }
- else if (args.SocketError == SocketError.Success)
- {
- disconnectToken.CompletionSource.SetResult(true);
- }
- else
- {
- disconnectToken.CompletionSource.SetException(new SocketException((int)args.SocketError));
- }
+ TransmissionResult result = new TransmissionResult(in args);
+
+ receiveToken.CompletionSource.SetResult(result);
TransmissionArgsPool.Return(args);
+ }
+ else if (expectedBytes > args.BytesTransferred && args.BytesTransferred > 0)
+ {
+ // receive the remaining parts of the buffer
- break;
+ int receivedBytes = args.BytesTransferred;
- case SocketAsyncOperation.Receive:
- AsyncTransmissionToken receiveToken = (AsyncTransmissionToken)args.UserToken;
+ args.SetBuffer(receivedBytes, expectedBytes - receivedBytes);
- if (receiveToken.CancellationToken.IsCancellationRequested)
- {
- receiveToken.CompletionSource.SetCanceled();
+ Connection.ReceiveAsync(args);
+ }
+ else
+ {
+ // no bytes were received, remote socket is dead
- TransmissionArgsPool.Return(args);
- }
- else if (args.SocketError == SocketError.Success)
- {
- Memory<byte> transmissionBuffer = args.MemoryBuffer;
- int expectedBytes = transmissionBuffer.Length;
+ receiveToken.CompletionSource.SetException(new SocketException((int)SocketError.HostDown));
- if (args.BytesTransferred == expectedBytes)
- {
- // buffer was fully received
+ TransmissionArgsPool.Return(args);
+ }
+ }
+ else
+ {
+ receiveToken.CompletionSource.SetException(new SocketException((int)args.SocketError));
- TransmissionResult result = new TransmissionResult(in args);
+ TransmissionArgsPool.Return(args);
+ }
+ }
- receiveToken.CompletionSource.SetResult(result);
+ private void CompleteSend(SocketAsyncEventArgs args)
+ {
+ AsyncTransmissionToken sendToken = (AsyncTransmissionToken)args.UserToken;
- TransmissionArgsPool.Return(args);
- }
- else if (expectedBytes > args.BytesTransferred && args.BytesTransferred > 0)
- {
- // receive the remaining parts of the buffer
+ if (sendToken.CancellationToken.IsCancellationRequested)
+ {
+ sendToken.CompletionSource.SetCanceled();
- int receivedBytes = args.BytesTransferred;
+ TransmissionArgsPool.Return(args);
+ }
+ else if (args.SocketError == SocketError.Success)
+ {
+ Memory<byte> transmissionBuffer = args.MemoryBuffer;
+ int remainingBytes = transmissionBuffer.Length;
- args.SetBuffer(receivedBytes, expectedBytes - receivedBytes);
+ if (args.BytesTransferred == remainingBytes)
+ {
+ // buffer was fully sent
- Connection.ReceiveAsync(args);
- }
- else
- {
- // no bytes were received, remote socket is dead
+ TransmissionResult result = new TransmissionResult(in args);
- receiveToken.CompletionSource.SetException(new SocketException((int)SocketError.HostDown));
+ sendToken.CompletionSource.SetResult(result);
- TransmissionArgsPool.Return(args);
- }
- }
- else
- {
- receiveToken.CompletionSource.SetException(new SocketException((int)args.SocketError));
+ TransmissionArgsPool.Return(args);
+ }
+ else if (remainingBytes > args.BytesTransferred && args.BytesTransferred > 0)
+ {
+ // send the remaining parts of the buffer
- TransmissionArgsPool.Return(args);
- }
+ int sentBytes = args.BytesTransferred;
- break;
+ args.SetBuffer(sentBytes, remainingBytes - sentBytes);
- case SocketAsyncOperation.Send:
- AsyncTransmissionToken sendToken = (AsyncTransmissionToken)args.UserToken;
+ Connection.SendAsync(args);
+ }
+ else
+ {
+ // no bytes were sent, remote socket is dead
- if (sendToken.CancellationToken.IsCancellationRequested)
- {
- sendToken.CompletionSource.SetCanceled();
+ sendToken.CompletionSource.SetException(new SocketException((int)SocketError.HostDown));
- TransmissionArgsPool.Return(args);
- }
- else if (args.SocketError == SocketError.Success)
- {
- Memory<byte> transmissionBuffer = args.MemoryBuffer;
- int remainingBytes = transmissionBuffer.Length;
+ TransmissionArgsPool.Return(args);
+ }
+ }
+ else
+ {
+ sendToken.CompletionSource.SetException(new SocketException((int)args.SocketError));
- if (args.BytesTransferred == remainingBytes)
- {
- // buffer was fully sent
+ TransmissionArgsPool.Return(args);
+ }
+ }
- TransmissionResult result = new TransmissionResult(in args);
+ /// <inheritdoc />
+ protected override bool CanTransmissionArgsBeReused(in SocketAsyncEventArgs args)
+ {
+ return true;
+ }
- sendToken.CompletionSource.SetResult(result);
+ /// <inheritdoc />
+ protected override SocketAsyncEventArgs CreateTransmissionArgs()
+ {
+ SocketAsyncEventArgs connectionArgs = new SocketAsyncEventArgs();
- TransmissionArgsPool.Return(args);
- }
- else if (remainingBytes > args.BytesTransferred && args.BytesTransferred > 0)
- {
- // send the remaining parts of the buffer
+ connectionArgs.Completed += HandleIoCompleted;
- int sentBytes = args.BytesTransferred;
+ return connectionArgs;
+ }
- args.SetBuffer(sentBytes, remainingBytes - sentBytes);
+ /// <inheritdoc />
+ protected override void DestroyTransmissionArgs(SocketAsyncEventArgs remoteConnectionArgs)
+ {
+ remoteConnectionArgs.Completed -= HandleIoCompleted;
+
+ remoteConnectionArgs.Dispose();
+ }
+
+ /// <inheritdoc />
+ protected override void HandleIoCompleted(object sender, SocketAsyncEventArgs args)
+ {
+ switch (args.LastOperation)
+ {
+ case SocketAsyncOperation.Connect:
+ CompleteConnect(args);
- Connection.SendAsync(args);
- }
- else
- {
- // no bytes were sent, remote socket is dead
+ break;
+
+ case SocketAsyncOperation.Disconnect:
+ CompleteDisconnect(args);
- sendToken.CompletionSource.SetException(new SocketException((int)SocketError.HostDown));
+ break;
+
+ case SocketAsyncOperation.Receive:
+ CompleteReceive(args);
- TransmissionArgsPool.Return(args);
- }
- }
- else
- {
- sendToken.CompletionSource.SetException(new SocketException((int)args.SocketError));
+ break;
- TransmissionArgsPool.Return(args);
- }
+ case SocketAsyncOperation.Send:
+ CompleteSend(args);
break;
@@ -253,9 +268,15 @@ namespace NetSharp.Sockets.Stream
public TransmissionResult Receive(byte[] buffer, SocketFlags flags = SocketFlags.None)
{
- int receivedBytes = Connection.Receive(buffer, flags);
+ int bytesToReceive = buffer.Length;
+ int bytesReceived = 0;
+
+ do
+ {
+ bytesReceived += Connection.Receive(buffer, bytesReceived, bytesToReceive - bytesReceived, flags);
+ } while (bytesReceived != 0 && bytesReceived < bytesToReceive);
- return new TransmissionResult(in buffer, in receivedBytes, Connection.RemoteEndPoint);
+ return new TransmissionResult(in buffer, in bytesReceived, Connection.RemoteEndPoint);
}
public ValueTask<TransmissionResult> ReceiveAsync(Memory<byte> receiveBuffer, SocketFlags flags = SocketFlags.None,
@@ -281,9 +302,15 @@ namespace NetSharp.Sockets.Stream
public TransmissionResult Send(byte[] buffer, SocketFlags flags = SocketFlags.None)
{
- int sentBytes = Connection.Send(buffer, flags);
+ int bytesToSend = buffer.Length;
+ int bytesSent = 0;
+
+ do
+ {
+ bytesSent += Connection.Send(buffer, bytesSent, bytesToSend - bytesSent, flags);
+ } while (bytesSent != 0 && bytesSent < bytesToSend);
- return new TransmissionResult(in buffer, in sentBytes, Connection.RemoteEndPoint);
+ return new TransmissionResult(in buffer, in bytesSent, Connection.RemoteEndPoint);
}
public ValueTask<TransmissionResult> SendAsync(Memory<byte> sendBuffer, SocketFlags flags = SocketFlags.None,
diff --git a/NetSharp/NetSharp/Sockets/Stream/StreamSocketServer.cs b/NetSharp/NetSharp/Sockets/Stream/StreamSocketServer.cs
@@ -11,16 +11,13 @@ namespace NetSharp.Sockets.Stream
public readonly struct StreamSocketServerOptions
{
public static readonly StreamSocketServerOptions Defaults =
- new StreamSocketServerOptions(NetworkPacket.TotalSize, Environment.ProcessorCount, 0);
+ new StreamSocketServerOptions(Environment.ProcessorCount, 0);
public readonly int ConcurrentAcceptCalls;
- public readonly int PacketSize;
public readonly ushort PreallocatedTransmissionArgs;
- public StreamSocketServerOptions(int packetSize, int concurrentAcceptCalls, ushort preallocatedTransmissionArgs)
+ public StreamSocketServerOptions(int concurrentAcceptCalls, ushort preallocatedTransmissionArgs)
{
- PacketSize = packetSize;
-
ConcurrentAcceptCalls = concurrentAcceptCalls;
PreallocatedTransmissionArgs = preallocatedTransmissionArgs;
@@ -36,13 +33,14 @@ namespace NetSharp.Sockets.Stream
/// <summary>
/// Constructs a new instance of the <see cref="StreamSocketServer" /> class.
/// </summary>
- /// <param name="serverOptions">Additional options to configure the server.</param>
+ /// <param name="serverOptions">
+ /// 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,
- serverOptions?.PacketSize ?? StreamSocketServerOptions.Defaults.PacketSize,
- serverOptions?.PreallocatedTransmissionArgs ?? StreamSocketServerOptions.Defaults.PreallocatedTransmissionArgs)
+ NetworkPacket.TotalSize, serverOptions?.PreallocatedTransmissionArgs ?? StreamSocketServerOptions.Defaults.PreallocatedTransmissionArgs)
{
this.serverOptions = serverOptions ?? StreamSocketServerOptions.Defaults;
}
@@ -90,17 +88,17 @@ namespace NetSharp.Sockets.Stream
if (clientArgs.SocketError == SocketError.Success)
{
- if (clientArgs.BytesTransferred == serverOptions.PacketSize)
+ if (clientArgs.BytesTransferred == NetworkPacket.TotalSize)
{
// buffer was fully received
- NetworkPacket request = NetworkPacket.Deserialise(receiveToken.RentedBuffer);
+ NetworkPacket.Deserialise(receiveToken.RentedBuffer, out NetworkPacket request);
NetworkPacket response = PacketHandler(in request, clientArgs.RemoteEndPoint);
if (!response.Equals(NetworkPacket.NullPacket))
{
- byte[] responseBuffer = BufferPool.Rent(serverOptions.PacketSize);
+ byte[] responseBuffer = BufferPool.Rent(NetworkPacket.TotalSize);
Memory<byte> responseBufferMemory = new Memory<byte>(responseBuffer);
NetworkPacket.Serialise(response, responseBufferMemory);
@@ -108,7 +106,7 @@ namespace NetSharp.Sockets.Stream
BufferPool.Return(receiveToken.RentedBuffer, true); // at this point the request buffer can be returned
receiveToken.RentedBuffer = responseBuffer;
- clientArgs.SetBuffer(responseBuffer, 0, serverOptions.PacketSize);
+ clientArgs.SetBuffer(responseBuffer, 0, NetworkPacket.TotalSize);
Send(clientArgs);
}
@@ -119,13 +117,13 @@ namespace NetSharp.Sockets.Stream
Receive(clientArgs);
}
}
- else if (serverOptions.PacketSize > clientArgs.BytesTransferred && clientArgs.BytesTransferred > 0)
+ else if (NetworkPacket.TotalSize > clientArgs.BytesTransferred && clientArgs.BytesTransferred > 0)
{
// receive the remaining parts of the buffer
int receivedBytes = clientArgs.BytesTransferred;
- clientArgs.SetBuffer(receivedBytes, serverOptions.PacketSize - receivedBytes);
+ clientArgs.SetBuffer(receivedBytes, NetworkPacket.TotalSize - receivedBytes);
Receive(clientArgs);
}
@@ -148,7 +146,7 @@ namespace NetSharp.Sockets.Stream
if (clientArgs.SocketError == SocketError.Success)
{
- if (clientArgs.BytesTransferred == serverOptions.PacketSize)
+ if (clientArgs.BytesTransferred == NetworkPacket.TotalSize)
{
// buffer was fully sent
@@ -158,13 +156,13 @@ namespace NetSharp.Sockets.Stream
Receive(clientArgs);
}
- else if (serverOptions.PacketSize > clientArgs.BytesTransferred && clientArgs.BytesTransferred > 0)
+ else if (NetworkPacket.TotalSize > clientArgs.BytesTransferred && clientArgs.BytesTransferred > 0)
{
// send the remaining parts of the buffer
int sentBytes = clientArgs.BytesTransferred;
- clientArgs.SetBuffer(sentBytes, serverOptions.PacketSize - sentBytes);
+ clientArgs.SetBuffer(sentBytes, NetworkPacket.TotalSize - sentBytes);
Send(clientArgs);
}
@@ -185,11 +183,11 @@ namespace NetSharp.Sockets.Stream
{
RemoteStreamClientToken clientToken = (RemoteStreamClientToken)clientArgs.UserToken;
- byte[] requestBuffer = BufferPool.Rent(serverOptions.PacketSize);
+ byte[] requestBuffer = BufferPool.Rent(NetworkPacket.TotalSize);
Memory<byte> requestBufferMemory = new Memory<byte>(requestBuffer);
clientToken.RentedBuffer = requestBuffer;
- clientArgs.SetBuffer(clientToken.RentedBuffer, 0, serverOptions.PacketSize);
+ clientArgs.SetBuffer(clientToken.RentedBuffer, 0, NetworkPacket.TotalSize);
bool operationPending = clientToken.ClientSocket.ReceiveAsync(clientArgs);
@@ -246,14 +244,17 @@ namespace NetSharp.Sockets.Stream
Accept(newAcceptArgs); // start a new accept operation to not miss any clients
CompleteAccept(args);
+
break;
case SocketAsyncOperation.Receive:
CompleteReceive(args);
+
break;
case SocketAsyncOperation.Send:
CompleteSend(args);
+
break;
default:
diff --git a/NetSharp/NetSharp/Utils/BiDictionary.cs b/NetSharp/NetSharp/Utils/BiDictionary.cs
@@ -5,8 +5,12 @@ namespace NetSharp.Utils
/// <summary>
/// Represents a concurrent two-way dictionary, that can be indexed by either a key or a value.
/// </summary>
- /// <typeparam name="K">The type of key that will be stored.</typeparam>
- /// <typeparam name="V">The type of value that will be stored.</typeparam>
+ /// <typeparam name="K">
+ /// The type of key that will be stored.
+ /// </typeparam>
+ /// <typeparam name="V">
+ /// The type of value that will be stored.
+ /// </typeparam>
public class BiDictionary<K, V>
{
/// <summary>
@@ -32,8 +36,12 @@ namespace NetSharp.Utils
/// <summary>
/// Indexes this instance with the given value.
/// </summary>
- /// <param name="index">The value whose key to get or set.</param>
- /// <returns>The fetched key.</returns>
+ /// <param name="index">
+ /// The value whose key to get or set.
+ /// </param>
+ /// <returns>
+ /// The fetched key.
+ /// </returns>
public K this[V index]
{
get
@@ -49,8 +57,12 @@ namespace NetSharp.Utils
/// <summary>
/// Indexes this instance with the given key.
/// </summary>
- /// <param name="index">The key whose value to get or set.</param>
- /// <returns>The fetched value.</returns>
+ /// <param name="index">
+ /// The key whose value to get or set.
+ /// </param>
+ /// <returns>
+ /// The fetched value.
+ /// </returns>
public V this[K index]
{
get
@@ -75,23 +87,37 @@ namespace NetSharp.Utils
/// <summary>
/// Whether this instance contains the given key.
/// </summary>
- /// <param name="key">The key to check.</param>
- /// <returns>Whether the given key was found.</returns>
+ /// <param name="key">
+ /// The key to check.
+ /// </param>
+ /// <returns>
+ /// Whether the given key was found.
+ /// </returns>
public bool ContainsKey(in K key) => keyToValueMap.ContainsKey(key);
/// <summary>
/// Whether this instance contains the given value.
/// </summary>
- /// <param name="value">The value to check.</param>
- /// <returns>Whether the given value was found.</returns>
+ /// <param name="value">
+ /// The value to check.
+ /// </param>
+ /// <returns>
+ /// Whether the given value was found.
+ /// </returns>
public bool ContainsValue(in V value) => valueToKeyMap.ContainsKey(value);
/// <summary>
/// Attempts to set the key associated with the given value.
/// </summary>
- /// <param name="value">The value whose key to set.</param>
- /// <param name="key">The new value for the value's associated key.</param>
- /// <returns>Whether the new key was correctly set.</returns>
+ /// <param name="value">
+ /// The value whose key to set.
+ /// </param>
+ /// <param name="key">
+ /// The new value for the value's associated key.
+ /// </param>
+ /// <returns>
+ /// Whether the new key was correctly set.
+ /// </returns>
public void SetOrUpdateKey(V value, K key)
{
valueToKeyMap.AddOrUpdate(value, key, (v, k) => key);
@@ -102,9 +128,15 @@ namespace NetSharp.Utils
/// <summary>
/// Attempts to set the value associated with the given key.
/// </summary>
- /// <param name="key">The key whose value to set.</param>
- /// <param name="value">The new value for the key's associated value.</param>
- /// <returns>Whether the new value was correctly set.</returns>
+ /// <param name="key">
+ /// The key whose value to set.
+ /// </param>
+ /// <param name="value">
+ /// The new value for the key's associated value.
+ /// </param>
+ /// <returns>
+ /// Whether the new value was correctly set.
+ /// </returns>
public void SetOrUpdateValue(K key, V value)
{
keyToValueMap.AddOrUpdate(key, value, (k, v) => value);
@@ -115,9 +147,15 @@ namespace NetSharp.Utils
/// <summary>
/// Attempts to remove the key associated with the given value.
/// </summary>
- /// <param name="value">The value whose key to remove.</param>
- /// <param name="key">The old key value.</param>
- /// <returns>Whether the given value had a valid key associated with it.</returns>
+ /// <param name="value">
+ /// The value whose key to remove.
+ /// </param>
+ /// <param name="key">
+ /// The old key value.
+ /// </param>
+ /// <returns>
+ /// Whether the given value had a valid key associated with it.
+ /// </returns>
public bool TryClearKey(in V value, out K key)
{
bool clearedValue = valueToKeyMap.TryRemove(value, out key);
@@ -130,9 +168,15 @@ namespace NetSharp.Utils
/// <summary>
/// Attempts to remove the value associated with the given key.
/// </summary>
- /// <param name="key">The key whose value to remove.</param>
- /// <param name="value">The old value.</param>
- /// <returns>Whether the given key had a valid valid associated with it.</returns>
+ /// <param name="key">
+ /// The key whose value to remove.
+ /// </param>
+ /// <param name="value">
+ /// The old value.
+ /// </param>
+ /// <returns>
+ /// Whether the given key had a valid valid associated with it.
+ /// </returns>
public bool TryClearValue(in K key, out V value)
{
bool clearedKey = keyToValueMap.TryRemove(key, out value);
@@ -145,9 +189,15 @@ namespace NetSharp.Utils
/// <summary>
/// Attempts to get the key associated with the given value.
/// </summary>
- /// <param name="value">The value whose key to get.</param>
- /// <param name="key">The returned key.</param>
- /// <returns>Whether the given value has a valid key associated with it.</returns>
+ /// <param name="value">
+ /// The value whose key to get.
+ /// </param>
+ /// <param name="key">
+ /// The returned key.
+ /// </param>
+ /// <returns>
+ /// Whether the given value has a valid key associated with it.
+ /// </returns>
public bool TryGetKey(in V value, out K key)
{
return valueToKeyMap.TryGetValue(value, out key);
@@ -156,9 +206,15 @@ namespace NetSharp.Utils
/// <summary>
/// Attempts to get the value associated with the given key.
/// </summary>
- /// <param name="key">The key whose value to get.</param>
- /// <param name="value">The returned value.</param>
- /// <returns>Whether the given key as a valid value associated with it.</returns>
+ /// <param name="key">
+ /// The key whose value to get.
+ /// </param>
+ /// <param name="value">
+ /// The returned value.
+ /// </param>
+ /// <returns>
+ /// Whether the given key as a valid value associated with it.
+ /// </returns>
public bool TryGetValue(in K key, out V value)
{
return keyToValueMap.TryGetValue(key, out value);
@@ -167,9 +223,15 @@ namespace NetSharp.Utils
/// <summary>
/// Attempts to set the key associated with the given value.
/// </summary>
- /// <param name="value">The value whose key to set.</param>
- /// <param name="key">The key which should be set for the given value.</param>
- /// <returns>Whether the given value was successfully set.</returns>
+ /// <param name="value">
+ /// The value whose key to set.
+ /// </param>
+ /// <param name="key">
+ /// The key which should be set for the given value.
+ /// </param>
+ /// <returns>
+ /// Whether the given value was successfully set.
+ /// </returns>
public bool TrySetKey(in V value, in K key)
{
K newKey = key;
@@ -184,9 +246,15 @@ namespace NetSharp.Utils
/// <summary>
/// Attempts to set the value associated with the given key.
/// </summary>
- /// <param name="key">The key whose value to set.</param>
- /// <param name="value">The value which should be set for the given key.</param>
- /// <returns>Whether the given key was successfully set.</returns>
+ /// <param name="key">
+ /// The key whose value to set.
+ /// </param>
+ /// <param name="value">
+ /// The value which should be set for the given key.
+ /// </param>
+ /// <returns>
+ /// Whether the given key was successfully set.
+ /// </returns>
public bool TrySetValue(in K key, in V value)
{
V newValue = value;
diff --git a/NetSharp/NetSharp/Utils/SlimObjectPool.cs b/NetSharp/NetSharp/Utils/SlimObjectPool.cs
@@ -5,7 +5,9 @@ namespace NetSharp.Utils
/// <summary>
/// Provides a lightweight implementation of an object pool for classes.
/// </summary>
- /// <typeparam name="T">The type of item stored in the pool.</typeparam>
+ /// <typeparam name="T">
+ /// The type of item stored in the pool.
+ /// </typeparam>
public class SlimObjectPool<T> where T : class
{
private readonly CanRebufferObjectPredicate canObjectBeRebufferedPredicate;
@@ -21,11 +23,21 @@ namespace NetSharp.Utils
/// <summary>
/// Constructs a new instance of the <see cref="SlimObjectPool{T}" /> class.
/// </summary>
- /// <param name="createDelegate">The delegate method to use to create new pooled object instances.</param>
- /// <param name="resetDelegate">The delegate method to use to reset used pooled object instances.</param>
- /// <param name="destroyDelegate">The delegate method to use to destroy pooled object instances that cannot be reused.</param>
- /// <param name="rebufferPredicate">The delegate method to use to decide whether an instance can be reused.</param>
- /// <param name="baseCollection">The underlying pooled object buffer to use.</param>
+ /// <param name="createDelegate">
+ /// The delegate method to use to create new pooled object instances.
+ /// </param>
+ /// <param name="resetDelegate">
+ /// The delegate method to use to reset used pooled object instances.
+ /// </param>
+ /// <param name="destroyDelegate">
+ /// The delegate method to use to destroy pooled object instances that cannot be reused.
+ /// </param>
+ /// <param name="rebufferPredicate">
+ /// The delegate method to use to decide whether an instance can be reused.
+ /// </param>
+ /// <param name="baseCollection">
+ /// The underlying pooled object buffer to use.
+ /// </param>
public SlimObjectPool(in CreateObjectDelegate createDelegate, in ResetObjectDelegate resetDelegate,
in DestroyObjectDelegate destroyDelegate, in CanRebufferObjectPredicate rebufferPredicate,
in IProducerConsumerCollection<T> baseCollection)
@@ -44,10 +56,18 @@ namespace NetSharp.Utils
/// <summary>
/// Constructs a new instance of the <see cref="SlimObjectPool{T}" /> class.
/// </summary>
- /// <param name="createDelegate">The delegate method to use to create new pooled object instances.</param>
- /// <param name="resetDelegate">The delegate method to use to reset used pooled object instances.</param>
- /// <param name="destroyDelegate">The delegate method to use to destroy pooled object instances that cannot be reused.</param>
- /// <param name="rebufferPredicate">The delegate method to use to decide whether an instance can be reused.</param>
+ /// <param name="createDelegate">
+ /// The delegate method to use to create new pooled object instances.
+ /// </param>
+ /// <param name="resetDelegate">
+ /// The delegate method to use to reset used pooled object instances.
+ /// </param>
+ /// <param name="destroyDelegate">
+ /// The delegate method to use to destroy pooled object instances that cannot be reused.
+ /// </param>
+ /// <param name="rebufferPredicate">
+ /// The delegate method to use to decide whether an instance can be reused.
+ /// </param>
public SlimObjectPool(in CreateObjectDelegate createDelegate, in ResetObjectDelegate resetDelegate,
in DestroyObjectDelegate destroyDelegate, in CanRebufferObjectPredicate rebufferPredicate)
: this(in createDelegate, in resetDelegate, in destroyDelegate, in rebufferPredicate, new ConcurrentBag<T>())
@@ -58,32 +78,44 @@ namespace NetSharp.Utils
/// Delegate method to check whether the given <paramref name="instance" /> can and should be placed back into the pool. If <c>true</c> is
/// returned, the <paramref name="instance" /> is reset and placed back into the pool. Otherwise, the instance is destroyed.
/// </summary>
- /// <param name="instance">The instance to check.</param>
- /// <returns>Whether the given instance should be placed back into the pool.</returns>
+ /// <param name="instance">
+ /// The instance to check.
+ /// </param>
+ /// <returns>
+ /// Whether the given instance should be placed back into the pool.
+ /// </returns>
public delegate bool CanRebufferObjectPredicate(in T instance);
/// <summary>
/// Delegate method for creating fresh <typeparamref name="T" /> instances to be stored in the pool.
/// </summary>
- /// <returns>A configured <typeparamref name="T" /> instance.</returns>
+ /// <returns>
+ /// A configured <typeparamref name="T" /> instance.
+ /// </returns>
public delegate T CreateObjectDelegate();
/// <summary>
/// Delegate method to destroy a used <paramref name="instance" /> which cannot be reused.
/// </summary>
- /// <param name="instance">The instance to destroy.</param>
+ /// <param name="instance">
+ /// The instance to destroy.
+ /// </param>
public delegate void DestroyObjectDelegate(T instance);
/// <summary>
/// Delegate method to reset a used <paramref name="instance" /> before placing it back into the pool.
/// </summary>
- /// <param name="instance">The instance which should be reset.</param>
+ /// <param name="instance">
+ /// The instance which should be reset.
+ /// </param>
public delegate void ResetObjectDelegate(T instance);
/// <summary>
/// Leases a new <typeparamref name="T" /> instance from the pool, and returns it.
/// </summary>
- /// <returns>The <typeparamref name="T" /> instance which was fetched from the pool.</returns>
+ /// <returns>
+ /// The <typeparamref name="T" /> instance which was fetched from the pool.
+ /// </returns>
public T Rent()
{
return objectBuffer.TryTake(out T result) ? result : createObjectDelegate();
@@ -92,7 +124,9 @@ namespace NetSharp.Utils
/// <summary>
/// Returns a previously leased <typeparamref name="T" /> instance to the pool.
/// </summary>
- /// <param name="instance">The previously leased instance which should be returned.</param>
+ /// <param name="instance">
+ /// The previously leased instance which should be returned.
+ /// </param>
public void Return(T instance)
{
if (canObjectBeRebufferedPredicate(instance))
diff --git a/NetSharp/NetSharp/Utils/TransmissionResult.cs b/NetSharp/NetSharp/Utils/TransmissionResult.cs
@@ -27,7 +27,9 @@ namespace NetSharp.Utils
/// <summary>
/// Initialises a new instance of the <see cref="TransmissionResult" /> struct.
/// </summary>
- /// <param name="args">The socket arguments associated with the transmission.</param>
+ /// <param name="args">
+ /// The socket arguments associated with the transmission.
+ /// </param>
internal TransmissionResult(in SocketAsyncEventArgs args)
{
Buffer = args.MemoryBuffer;
@@ -38,9 +40,15 @@ namespace NetSharp.Utils
/// <summary>
/// Initialises a new instance of the <see cref="TransmissionResult" /> struct.
/// </summary>
- /// <param name="buffer">The buffer associated with the transmission.</param>
- /// <param name="count">The number of bytes written to or read from the buffer.</param>
- /// <param name="remoteEndPoint">The remote end point associated with the transmission.</param>
+ /// <param name="buffer">
+ /// The buffer associated with the transmission.
+ /// </param>
+ /// <param name="count">
+ /// The number of bytes written to or read from the buffer.
+ /// </param>
+ /// <param name="remoteEndPoint">
+ /// The remote end point associated with the transmission.
+ /// </param>
internal TransmissionResult(in byte[] buffer, in int count, in EndPoint remoteEndPoint)
{
Buffer = buffer;
diff --git a/NetSharp/NetSharpExamples/Benchmarks/TcpSocketServerBenchmark.cs b/NetSharp/NetSharpExamples/Benchmarks/TcpSocketServerBenchmark.cs
@@ -20,46 +20,6 @@ namespace NetSharpExamples.Benchmarks
private double[] ClientBandwidths;
- /// <inheritdoc />
- public async Task RunAsync()
- {
- CancellationTokenSource serverCts = new CancellationTokenSource();
-
- int clientCount = Environment.ProcessorCount / 2;
-
- Console.WriteLine($"TCP Server Benchmark started!");
-
- StreamSocketServerOptions serverOptions = new StreamSocketServerOptions(NetworkPacket.TotalSize,
- clientCount, (ushort)clientCount);
-
- StreamSocketServer server = new StreamSocketServer(AddressFamily.InterNetwork, ProtocolType.Tcp,
- SocketServer.DefaultPacketHandler, serverOptions);
-
- server.Bind(ServerEndPoint);
-
- Task serverTask = Task.Factory.StartNew(() =>
- {
- server.RunAsync(serverCts.Token).GetAwaiter().GetResult();
- }, TaskCreationOptions.LongRunning);
-
- 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}");
-
- serverCts.Cancel();
-
- await serverTask;
-
- Console.WriteLine($"TCP Server Benchmark finished!");
- }
-
private Task BenchmarkClientTask(object idObj)
{
int id = (int)idObj;
@@ -101,14 +61,6 @@ namespace NetSharpExamples.Benchmarks
break;
}
-#if DEBUG
- lock (typeof(Console))
- {
- Console.WriteLine($"[Client {id}, Packet {i}] Sent {sentBytes} bytes to {remoteEndPoint}");
- Console.WriteLine($"[Client {id}, Packet {i}] >>>> {Encoding.UTF8.GetString(sendBuffer)}");
- }
-#endif
-
int totalReceived = 0;
do
{
@@ -124,23 +76,8 @@ namespace NetSharpExamples.Benchmarks
benchmarkHelper.StopRttStopwatch();
benchmarkHelper.StopBandwidthStopwatch();
-#if DEBUG
- lock (typeof(Console))
- {
- Console.WriteLine($"[Client {id}, Packet {i}] Received {receivedBytes} bytes from {remoteEndPoint}");
- Console.WriteLine($"[Client {id}, Packet {i}] <<<< {Encoding.UTF8.GetString(receiveBuffer)}");
- }
-#endif
-
benchmarkHelper.UpdateRttStats(id);
- /*
- lock (typeof(Console))
- {
- Console.WriteLine($"[Client {id}] Current RTT: {benchmarkHelper.RttTicks} ticks, {benchmarkHelper.RttMs} ms");
- }
- */
-
benchmarkHelper.ResetRttStopwatch();
}
@@ -154,5 +91,44 @@ namespace NetSharpExamples.Benchmarks
return Task.CompletedTask;
}
+
+ /// <inheritdoc />
+ public async Task RunAsync()
+ {
+ CancellationTokenSource serverCts = new CancellationTokenSource();
+
+ int clientCount = Environment.ProcessorCount / 2;
+
+ Console.WriteLine($"TCP Server Benchmark started!");
+
+ StreamSocketServerOptions serverOptions = new StreamSocketServerOptions(clientCount, (ushort)clientCount);
+
+ StreamSocketServer server = new StreamSocketServer(AddressFamily.InterNetwork, ProtocolType.Tcp,
+ SocketServer.DefaultPacketHandler, serverOptions);
+
+ server.Bind(ServerEndPoint);
+
+ Task serverTask = Task.Factory.StartNew(() =>
+ {
+ server.RunAsync(serverCts.Token).GetAwaiter().GetResult();
+ }, TaskCreationOptions.LongRunning);
+
+ 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}");
+
+ serverCts.Cancel();
+
+ await serverTask;
+
+ Console.WriteLine($"TCP Server Benchmark finished!");
+ }
}
}
\ No newline at end of file
diff --git a/NetSharp/NetSharpExamples/Benchmarks/UdpSocketServerBenchmark.cs b/NetSharp/NetSharpExamples/Benchmarks/UdpSocketServerBenchmark.cs
@@ -20,46 +20,6 @@ namespace NetSharpExamples.Benchmarks
private double[] ClientBandwidths;
- /// <inheritdoc />
- public async Task RunAsync()
- {
- CancellationTokenSource serverCts = new CancellationTokenSource();
-
- int clientCount = Environment.ProcessorCount / 2;
-
- Console.WriteLine($"UDP Server Benchmark started!");
-
- DatagramSocketServerOptions serverOptions = new DatagramSocketServerOptions(NetworkPacket.TotalSize,
- clientCount, (ushort)clientCount);
-
- DatagramSocketServer server = new DatagramSocketServer(AddressFamily.InterNetwork, ProtocolType.Udp,
- SocketServer.DefaultPacketHandler, serverOptions);
-
- server.Bind(ServerEndPoint);
-
- Task serverTask = Task.Factory.StartNew(() =>
- {
- server.RunAsync(serverCts.Token).GetAwaiter().GetResult();
- }, TaskCreationOptions.LongRunning);
-
- 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}");
-
- serverCts.Cancel();
-
- await serverTask;
-
- Console.WriteLine($"UDP Server Benchmark finished!");
- }
-
private Task BenchmarkClientTask(object idObj)
{
int id = (int)idObj;
@@ -89,35 +49,12 @@ namespace NetSharpExamples.Benchmarks
benchmarkHelper.StartRttStopwatch();
int sentBytes = clientSocket.SendTo(sendBuffer, remoteEndPoint);
-#if DEBUG
- lock (typeof(Console))
- {
- Console.WriteLine($"[Client {id}, Packet {i}] Sent {sentBytes} bytes to {remoteEndPoint}");
- Console.WriteLine($"[Client {id}, Packet {i}] >>>> {Encoding.UTF8.GetString(sendBuffer)}");
- }
-#endif
-
int receivedBytes = clientSocket.ReceiveFrom(receiveBuffer, ref remoteEndPoint);
benchmarkHelper.StopRttStopwatch();
benchmarkHelper.StopBandwidthStopwatch();
-#if DEBUG
- lock (typeof(Console))
- {
- Console.WriteLine($"[Client {id}, Packet {i}] Received {receivedBytes} bytes from {remoteEndPoint}");
- Console.WriteLine($"[Client {id}, Packet {i}] <<<< {Encoding.UTF8.GetString(receiveBuffer)}");
- }
-#endif
-
benchmarkHelper.UpdateRttStats(id);
- /*
- lock (typeof(Console))
- {
- Console.WriteLine($"[Client {id}] Current RTT: {benchmarkHelper.RttTicks} ticks, {benchmarkHelper.RttMs} ms");
- }
- */
-
benchmarkHelper.ResetRttStopwatch();
}
@@ -128,5 +65,44 @@ namespace NetSharpExamples.Benchmarks
return Task.CompletedTask;
}
+
+ /// <inheritdoc />
+ public async Task RunAsync()
+ {
+ CancellationTokenSource serverCts = new CancellationTokenSource();
+
+ int clientCount = Environment.ProcessorCount / 2;
+
+ Console.WriteLine($"UDP Server Benchmark started!");
+
+ DatagramSocketServerOptions serverOptions = new DatagramSocketServerOptions(clientCount, (ushort)clientCount);
+
+ DatagramSocketServer server = new DatagramSocketServer(AddressFamily.InterNetwork, ProtocolType.Udp,
+ SocketServer.DefaultPacketHandler, serverOptions);
+
+ server.Bind(ServerEndPoint);
+
+ Task serverTask = Task.Factory.StartNew(() =>
+ {
+ server.RunAsync(serverCts.Token).GetAwaiter().GetResult();
+ }, TaskCreationOptions.LongRunning);
+
+ 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}");
+
+ serverCts.Cancel();
+
+ await serverTask;
+
+ Console.WriteLine($"UDP Server Benchmark finished!");
+ }
}
}
\ No newline at end of file
diff --git a/NetSharp/NetSharpExamples/Examples/TcpSocketClientExample.cs b/NetSharp/NetSharpExamples/Examples/TcpSocketClientExample.cs
@@ -15,13 +15,13 @@ namespace NetSharpExamples.Examples
/// <inheritdoc />
public async Task RunAsync()
{
- StreamSocketClientOptions clientOptions = new StreamSocketClientOptions(NetworkPacket.TotalSize, 2);
+ StreamSocketClientOptions clientOptions = new StreamSocketClientOptions(2);
using StreamSocketClient client = new StreamSocketClient(AddressFamily.InterNetwork, ProtocolType.Tcp, clientOptions);
Encoding dataEncoding = UdpSocketServerExample.ServerEncoding;
- byte[] sendBuffer = new byte[clientOptions.PacketSize];
- byte[] receiveBuffer = new byte[clientOptions.PacketSize];
+ byte[] sendBuffer = new byte[NetworkPacket.TotalSize];
+ byte[] receiveBuffer = new byte[NetworkPacket.TotalSize];
EndPoint remoteEndPoint = TcpSocketServerExample.ServerEndPoint;
diff --git a/NetSharp/NetSharpExamples/Examples/TcpSocketServerExample.cs b/NetSharp/NetSharpExamples/Examples/TcpSocketServerExample.cs
@@ -33,7 +33,7 @@ namespace NetSharpExamples.Examples
public Task RunAsync()
{
StreamSocketServerOptions serverOptions =
- new StreamSocketServerOptions(NetworkPacket.TotalSize, Environment.ProcessorCount, 2);
+ new StreamSocketServerOptions(Environment.ProcessorCount, 2);
using StreamSocketServer server =
new StreamSocketServer(AddressFamily.InterNetwork, ProtocolType.Tcp, ServerPacketHandler, serverOptions);
diff --git a/NetSharp/NetSharpExamples/Examples/UdpSocketClientExample.cs b/NetSharp/NetSharpExamples/Examples/UdpSocketClientExample.cs
@@ -15,13 +15,13 @@ namespace NetSharpExamples.Examples
/// <inheritdoc />
public async Task RunAsync()
{
- DatagramSocketClientOptions clientOptions = new DatagramSocketClientOptions(NetworkPacket.TotalSize, 2);
+ DatagramSocketClientOptions clientOptions = new DatagramSocketClientOptions(2);
using DatagramSocketClient client = new DatagramSocketClient(AddressFamily.InterNetwork, ProtocolType.Udp, clientOptions);
Encoding dataEncoding = UdpSocketServerExample.ServerEncoding;
- byte[] sendBuffer = new byte[clientOptions.PacketSize];
- byte[] receiveBuffer = new byte[clientOptions.PacketSize];
+ byte[] sendBuffer = new byte[NetworkPacket.TotalSize];
+ byte[] receiveBuffer = new byte[NetworkPacket.TotalSize];
EndPoint remoteEndPoint = UdpSocketServerExample.ServerEndPoint;
diff --git a/NetSharp/NetSharpExamples/Examples/UdpSocketServerExample.cs b/NetSharp/NetSharpExamples/Examples/UdpSocketServerExample.cs
@@ -33,7 +33,7 @@ namespace NetSharpExamples.Examples
public Task RunAsync()
{
DatagramSocketServerOptions serverOptions =
- new DatagramSocketServerOptions(NetworkPacket.TotalSize, Environment.ProcessorCount, 2);
+ new DatagramSocketServerOptions(Environment.ProcessorCount, 2);
using DatagramSocketServer server =
new DatagramSocketServer(AddressFamily.InterNetwork, ProtocolType.Udp, ServerPacketHandler, serverOptions);