commit 9c793631ee741cdc79f1ecef66d00b906e94ad1b parent 487994f274d6c653e217d4105d3bdca8f4375c36 Author: Mikolaj Lenczewski <mikolaj.lenczewski308@gmail.com> Date: Thu, 25 Jun 2020 18:28:23 +0100 Updated docs and fixed datagram benchmark execution issues (involving socket reuse). Diffstat:
29 files changed, 1197 insertions(+), 931 deletions(-)
diff --git a/NetSharp/NetSharp.Benchmarks/BenchmarkHelper.cs b/NetSharp/NetSharp.Benchmarks/BenchmarkHelper.cs @@ -42,20 +42,14 @@ namespace NetSharp.Benchmarks double megabytes = sentPacketCount * packetSize / 1_000_000.0; double bandwidth = megabytes / (millis / 1000.0); - lock (typeof(Console)) - { - Console.WriteLine($"[Client {clientId}] Sent {sentPacketCount} packets (of size {packetSize} bytes; {megabytes / 1000} gigabytes [one-way]) in {millis} milliseconds"); - Console.WriteLine($"[Client {clientId}] Approximate bandwidth: {bandwidth:F3} MBps"); - } + Console.WriteLine($"[Client {clientId}] Sent {sentPacketCount} packets (of size {packetSize} bytes; {megabytes / 1000} gigabytes [one-way]) in {millis} milliseconds"); + Console.WriteLine($"[Client {clientId}] Approximate bandwidth: {bandwidth:F3} MBps"); } public void PrintRttStats(int clientId) { - lock (typeof(Console)) - { - Console.WriteLine($"[Client {clientId}] Min RTT: {minRttTicks} ticks, {minRttMs} ms"); - Console.WriteLine($"[Client {clientId}] Max RTT: {maxRttTicks} ticks, {maxRttMs} ms"); - } + Console.WriteLine($"[Client {clientId}] Min RTT: {minRttTicks} ticks, {minRttMs} ms"); + Console.WriteLine($"[Client {clientId}] Max RTT: {maxRttTicks} ticks, {maxRttMs} ms"); } public void ResetStopwatch() diff --git a/NetSharp/NetSharp.Benchmarks/Benchmarks/Datagram Network Connection Benchmarks/DatagramNetworkReaderBenchmark.cs b/NetSharp/NetSharp.Benchmarks/Benchmarks/Datagram Network Connection Benchmarks/DatagramNetworkReaderBenchmark.cs @@ -1,110 +0,0 @@ -using System; -using System.Linq; -using System.Net; -using System.Net.Sockets; -using System.Threading; -using System.Threading.Tasks; - -using NetSharp.Raw.Datagram; - -namespace NetSharp.Benchmarks.Benchmarks.Datagram_Network_Connection_Benchmarks -{ - internal class DatagramNetworkReaderBenchmark : INetSharpBenchmark - { - private const int PacketSize = 8192, PacketCount = 1_000_000, ClientCount = 12; - private static readonly ManualResetEventSlim ServerReadyEvent = new ManualResetEventSlim(); - private double[] ClientBandwidths; - - /// <inheritdoc /> - public string Name { get; } = "Raw Datagram Network Reader Benchmark"; - - private static bool RequestHandler(EndPoint remoteEndPoint, in ReadOnlyMemory<byte> requestBuffer, int receivedRequestBytes, - in Memory<byte> responseBuffer) - { - requestBuffer.CopyTo(responseBuffer); - - return true; - } - - private Task BenchmarkClientTask(object idObj) - { - int id = (int) idObj; - - BenchmarkHelper benchmarkHelper = new BenchmarkHelper(); - - Socket clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); - clientSocket.Bind(Program.Constants.ClientEndPoint); - - ServerReadyEvent.Wait(); - - byte[] sendBuffer = new byte[PacketSize]; - byte[] receiveBuffer = new byte[PacketSize]; - - EndPoint remoteEndPoint = Program.Constants.ServerEndPoint; - - lock (typeof(Console)) - { - Console.WriteLine($"[Client {id}] Starting client; sending messages to {remoteEndPoint}"); - } - - for (int i = 0; i < PacketCount; i++) - { - byte[] packetBuffer = Program.Constants.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); - - clientSocket.Close(); - clientSocket.Dispose(); - - return Task.CompletedTask; - } - - /// <inheritdoc /> - public async Task RunAsync() - { - if (PacketCount > 10_000) - { - Console.WriteLine($"{PacketCount} packets will be sent per client. This could take a long time (maybe more than a minute)!"); - } - - 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); - } - - EndPoint defaultRemoteEndPoint = new IPEndPoint(IPAddress.Any, 0); - - Socket rawSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); - rawSocket.Bind(Program.Constants.ServerEndPoint); - - using RawDatagramNetworkReader reader = new RawDatagramNetworkReader(ref rawSocket, RequestHandler, defaultRemoteEndPoint, PacketSize); - reader.Start(ClientCount); - - ServerReadyEvent.Set(); - - await Task.WhenAll(clientTasks); - - Console.WriteLine($"Total estimated bandwidth: {ClientBandwidths.Sum():F3}"); - - reader.Shutdown(); - - rawSocket.Close(); - rawSocket.Dispose(); - } - } -} -\ No newline at end of file diff --git a/NetSharp/NetSharp.Benchmarks/Benchmarks/Datagram Network Connection Benchmarks/DatagramNetworkWriterAsyncBenchmark.cs b/NetSharp/NetSharp.Benchmarks/Benchmarks/Datagram Network Connection Benchmarks/DatagramNetworkWriterAsyncBenchmark.cs @@ -1,98 +0,0 @@ -using System; -using System.Net; -using System.Net.Sockets; -using System.Threading; -using System.Threading.Tasks; - -using NetSharp.Raw.Datagram; - -namespace NetSharp.Benchmarks.Benchmarks.Datagram_Network_Connection_Benchmarks -{ - internal class DatagramNetworkWriterAsyncBenchmark : INetSharpBenchmark - { - private const int PacketSize = 8192, PacketCount = 1_000_000; - private static readonly ManualResetEventSlim ServerReadyEvent = new ManualResetEventSlim(); - - /// <inheritdoc /> - public string Name { get; } = "Raw Datagram Network Writer Benchmark (Asynchronous)"; - - private static Task ServerTask(CancellationToken cancellationToken) - { - using Socket server = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); - - server.Bind(Program.Constants.ServerEndPoint); - ServerReadyEvent.Set(); - - byte[] transmissionBuffer = new byte[PacketSize]; - - EndPoint remoteEndPoint = new IPEndPoint(IPAddress.Any, 0); - - while (!cancellationToken.IsCancellationRequested) - { - server.ReceiveFrom(transmissionBuffer, ref remoteEndPoint); - - server.SendTo(transmissionBuffer, remoteEndPoint); - } - - server.Close(); - - return Task.CompletedTask; - } - - /// <inheritdoc /> - public async Task RunAsync() - { - if (PacketCount > 10_000) - { - Console.WriteLine($"{PacketCount} packets will be sent per client. This could take a long time (maybe more than a minute)!"); - } - - EndPoint defaultRemoteEndPoint = new IPEndPoint(IPAddress.Any, 0); - - Socket rawSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); - rawSocket.Bind(Program.Constants.ClientEndPoint); - - using RawDatagramNetworkWriter writer = new RawDatagramNetworkWriter(ref rawSocket, defaultRemoteEndPoint, PacketSize); - - using CancellationTokenSource serverCts = new CancellationTokenSource(); - Task serverTask = Task.Factory.StartNew(state => ServerTask((CancellationToken) state), serverCts.Token, TaskCreationOptions.LongRunning); - - ServerReadyEvent.Wait(); - - BenchmarkHelper benchmarkHelper = new BenchmarkHelper(); - - byte[] sendBuffer = new byte[PacketSize]; - byte[] receiveBuffer = new byte[PacketSize]; - - for (int i = 0; i < PacketCount; i++) - { - byte[] packetBuffer = Program.Constants.ServerEncoding.GetBytes($"[Client 0] Hello World! (Packet {i})"); - packetBuffer.CopyTo(sendBuffer, 0); - - benchmarkHelper.StartStopwatch(); - int sendResult = await writer.WriteAsync(Program.Constants.ServerEndPoint, sendBuffer); - - int receiveResult = await writer.ReadAsync(Program.Constants.ServerEndPoint, receiveBuffer); - benchmarkHelper.StopStopwatch(); - - benchmarkHelper.SnapshotRttStats(); - } - - benchmarkHelper.PrintBandwidthStats(0, PacketCount, PacketSize); - benchmarkHelper.PrintRttStats(0); - - serverCts.Cancel(); - try - { - serverTask.Dispose(); - } - catch (Exception) - { - // ignored - } - - rawSocket.Close(); - rawSocket.Dispose(); - } - } -} -\ No newline at end of file diff --git a/NetSharp/NetSharp.Benchmarks/Benchmarks/Datagram Network Connection Benchmarks/DatagramNetworkWriterSyncBenchmark.cs b/NetSharp/NetSharp.Benchmarks/Benchmarks/Datagram Network Connection Benchmarks/DatagramNetworkWriterSyncBenchmark.cs @@ -1,94 +0,0 @@ -using System; -using System.Net; -using System.Net.Sockets; -using System.Threading; -using System.Threading.Tasks; - -using NetSharp.Raw.Datagram; - -namespace NetSharp.Benchmarks.Benchmarks.Datagram_Network_Connection_Benchmarks -{ - internal class DatagramNetworkWriterSyncBenchmark : INetSharpBenchmark - { - private const int PacketSize = 8192, PacketCount = 1_000_000; - private static readonly ManualResetEventSlim ServerReadyEvent = new ManualResetEventSlim(); - - /// <inheritdoc /> - public string Name { get; } = "Raw Datagram Network Writer Benchmark (Synchronous)"; - - private static Task ServerTask(CancellationToken cancellationToken) - { - using Socket server = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); - - server.Bind(Program.Constants.ServerEndPoint); - ServerReadyEvent.Set(); - - byte[] transmissionBuffer = new byte[PacketSize]; - - EndPoint remoteEndPoint = new IPEndPoint(IPAddress.Any, 0); - - while (!cancellationToken.IsCancellationRequested) - { - int received = server.ReceiveFrom(transmissionBuffer, ref remoteEndPoint); - - int sent = server.SendTo(transmissionBuffer, remoteEndPoint); - } - - server.Close(); - - return Task.CompletedTask; - } - - /// <inheritdoc /> - public Task RunAsync() - { - if (PacketCount > 10_000) - { - Console.WriteLine($"{PacketCount} packets will be sent per client. This could take a long time (maybe more than a minute)!"); - } - - EndPoint defaultRemoteEndPoint = new IPEndPoint(IPAddress.Any, 0); - - Socket rawSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); - rawSocket.Bind(Program.Constants.ClientEndPoint); - - using RawDatagramNetworkWriter writer = new RawDatagramNetworkWriter(ref rawSocket, defaultRemoteEndPoint, PacketSize); - - using CancellationTokenSource serverCts = new CancellationTokenSource(); - Task serverTask = Task.Factory.StartNew(state => ServerTask((CancellationToken) state), serverCts.Token, TaskCreationOptions.LongRunning); - - ServerReadyEvent.Wait(); - - BenchmarkHelper benchmarkHelper = new BenchmarkHelper(); - - byte[] sendBuffer = new byte[PacketSize]; - byte[] receiveBuffer = new byte[PacketSize]; - - EndPoint remoteEndPoint = Program.Constants.ServerEndPoint; - - for (int i = 0; i < PacketCount; i++) - { - byte[] packetBuffer = Program.Constants.ServerEncoding.GetBytes($"[Client 0] Hello World! (Packet {i})"); - packetBuffer.CopyTo(sendBuffer, 0); - - benchmarkHelper.StartStopwatch(); - int sendResult = writer.Write(Program.Constants.ServerEndPoint, sendBuffer); - - int receiveResult = writer.Read(ref remoteEndPoint, receiveBuffer); - benchmarkHelper.StopStopwatch(); - - benchmarkHelper.SnapshotRttStats(); - } - - benchmarkHelper.PrintBandwidthStats(0, PacketCount, PacketSize); - benchmarkHelper.PrintRttStats(0); - - serverCts.Cancel(); - - rawSocket.Close(); - rawSocket.Dispose(); - - return Task.CompletedTask; - } - } -} -\ No newline at end of file diff --git a/NetSharp/NetSharp.Benchmarks/Benchmarks/Datagram Network Connection Benchmarks/RawDatagramNetworkReaderMultiClientBenchmark.cs b/NetSharp/NetSharp.Benchmarks/Benchmarks/Datagram Network Connection Benchmarks/RawDatagramNetworkReaderMultiClientBenchmark.cs @@ -0,0 +1,115 @@ +using System; +using System.Linq; +using System.Net; +using System.Net.Sockets; +using System.Threading; +using System.Threading.Tasks; + +using NetSharp.Raw.Datagram; + +namespace NetSharp.Benchmarks.Benchmarks.Datagram_Network_Connection_Benchmarks +{ + internal class RawDatagramNetworkReaderMultiClientBenchmark : INetSharpBenchmark + { + private const int PacketSize = 8192, PacketCount = 1_000_000, ClientCount = 8; + private static readonly ManualResetEventSlim ServerReadyEvent = new ManualResetEventSlim(false); + private double[] ClientBandwidths; + + /// <inheritdoc /> + public string Name { get; } = "Raw Datagram Network Reader (Multiple Clients) Benchmark"; + + private static bool RequestHandler(EndPoint remoteEndPoint, in ReadOnlyMemory<byte> requestBuffer, int receivedRequestBytes, + in Memory<byte> responseBuffer) + { + requestBuffer.CopyTo(responseBuffer); + + return true; + } + + private Task BenchmarkClientTask(object idObj) + { + int id = (int) idObj; + + BenchmarkHelper benchmarkHelper = new BenchmarkHelper(); + + byte[] sendBuffer = new byte[PacketSize]; + byte[] receiveBuffer = new byte[PacketSize]; + + EndPoint remoteEndPoint = Program.Constants.ServerEndPoint; + + using Socket clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); + clientSocket.Bind(Program.Constants.ClientEndPoint); + + lock (typeof(Console)) + { + Console.WriteLine($"[Client {id}] Starting client; sending messages to {remoteEndPoint}"); + } + + benchmarkHelper.ResetStopwatch(); + + ServerReadyEvent.Wait(); + + for (int i = 0; i < PacketCount; i++) + { + byte[] packetBuffer = Program.Constants.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(); + } + + lock (typeof(Console)) + { + benchmarkHelper.PrintBandwidthStats(id, PacketCount, PacketSize); + benchmarkHelper.PrintRttStats(id); + } + + ClientBandwidths[id] = benchmarkHelper.CalcBandwidth(PacketCount, PacketSize); + + clientSocket.Close(); + + return Task.CompletedTask; + } + + /// <inheritdoc /> + public async Task RunAsync() + { + if (PacketCount > 10_000) + { + Console.WriteLine($"{PacketCount} packets will be sent per client. This could take a long time (maybe more than a minute)!"); + } + + 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); + } + + EndPoint defaultRemoteEndPoint = new IPEndPoint(IPAddress.Any, 0); + + Socket rawSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); + rawSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true); + rawSocket.Bind(Program.Constants.ServerEndPoint); + + using RawDatagramNetworkReader reader = new RawDatagramNetworkReader(ref rawSocket, RequestHandler, defaultRemoteEndPoint, PacketSize); + reader.Start(ClientCount); + + ServerReadyEvent.Set(); + + await Task.WhenAll(clientTasks); + + Console.WriteLine($"Total estimated bandwidth: {ClientBandwidths.Sum():F3}"); + + reader.Shutdown(); + + rawSocket.Close(); + rawSocket.Dispose(); + } + } +} +\ No newline at end of file diff --git a/NetSharp/NetSharp.Benchmarks/Benchmarks/Datagram Network Connection Benchmarks/RawDatagramNetworkReaderSingleClientBenchmark.cs b/NetSharp/NetSharp.Benchmarks/Benchmarks/Datagram Network Connection Benchmarks/RawDatagramNetworkReaderSingleClientBenchmark.cs @@ -0,0 +1,111 @@ +using System; +using System.Linq; +using System.Net; +using System.Net.Sockets; +using System.Threading; +using System.Threading.Tasks; + +using NetSharp.Raw.Datagram; + +namespace NetSharp.Benchmarks.Benchmarks.Datagram_Network_Connection_Benchmarks +{ + internal class RawDatagramNetworkReaderSingleClientBenchmark : INetSharpBenchmark + { + private const int PacketSize = 8192, PacketCount = 1_000_000; + private static readonly ManualResetEventSlim ServerReadyEvent = new ManualResetEventSlim(false); + private double[] ClientBandwidths; + + /// <inheritdoc /> + public string Name { get; } = "Raw Datagram Network Reader (Single Client) Benchmark"; + + private static bool RequestHandler(EndPoint remoteEndPoint, in ReadOnlyMemory<byte> requestBuffer, int receivedRequestBytes, + in Memory<byte> responseBuffer) + { + requestBuffer.CopyTo(responseBuffer); + + return true; + } + + private Task BenchmarkClientTask(object idObj) + { + int id = (int) idObj; + + BenchmarkHelper benchmarkHelper = new BenchmarkHelper(); + + byte[] sendBuffer = new byte[PacketSize]; + byte[] receiveBuffer = new byte[PacketSize]; + + EndPoint remoteEndPoint = Program.Constants.ServerEndPoint; + + using Socket clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); + clientSocket.Bind(Program.Constants.ClientEndPoint); + + lock (typeof(Console)) + { + Console.WriteLine($"[Client {id}] Starting client; sending messages to {remoteEndPoint}"); + } + + benchmarkHelper.ResetStopwatch(); + + ServerReadyEvent.Wait(); + + for (int i = 0; i < PacketCount; i++) + { + byte[] packetBuffer = Program.Constants.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(); + } + + lock (typeof(Console)) + { + benchmarkHelper.PrintBandwidthStats(id, PacketCount, PacketSize); + benchmarkHelper.PrintRttStats(id); + } + + ClientBandwidths[id] = benchmarkHelper.CalcBandwidth(PacketCount, PacketSize); + + clientSocket.Close(); + + return Task.CompletedTask; + } + + /// <inheritdoc /> + public async Task RunAsync() + { + if (PacketCount > 10_000) + { + Console.WriteLine($"{PacketCount} packets will be sent per client. This could take a long time (maybe more than a minute)!"); + } + + ClientBandwidths = new double[1]; + Task[] clientTasks = new Task[] { Task.Factory.StartNew(BenchmarkClientTask, 0, TaskCreationOptions.LongRunning) }; + + EndPoint defaultRemoteEndPoint = new IPEndPoint(IPAddress.Any, 0); + + Socket rawSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); + rawSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true); + rawSocket.Bind(Program.Constants.ServerEndPoint); + + using RawDatagramNetworkReader reader = new RawDatagramNetworkReader(ref rawSocket, RequestHandler, defaultRemoteEndPoint, PacketSize); + reader.Start(1); + + ServerReadyEvent.Set(); + + await Task.WhenAll(clientTasks); + + Console.WriteLine($"Total estimated bandwidth: {ClientBandwidths.Sum():F3}"); + + reader.Shutdown(); + + rawSocket.Close(); + rawSocket.Dispose(); + } + } +} +\ No newline at end of file diff --git a/NetSharp/NetSharp.Benchmarks/Benchmarks/Datagram Network Connection Benchmarks/RawDatagramNetworkWriterAsyncBenchmark.cs b/NetSharp/NetSharp.Benchmarks/Benchmarks/Datagram Network Connection Benchmarks/RawDatagramNetworkWriterAsyncBenchmark.cs @@ -0,0 +1,101 @@ +using System; +using System.Net; +using System.Net.Sockets; +using System.Threading; +using System.Threading.Tasks; + +using NetSharp.Raw.Datagram; + +namespace NetSharp.Benchmarks.Benchmarks.Datagram_Network_Connection_Benchmarks +{ + internal class RawDatagramNetworkWriterAsyncBenchmark : INetSharpBenchmark + { + private const int PacketSize = 8192, PacketCount = 1_000_000; + private static readonly ManualResetEventSlim ServerReadyEvent = new ManualResetEventSlim(false); + + /// <inheritdoc /> + public string Name { get; } = "Raw Datagram Network Writer Benchmark (Asynchronous)"; + + private static Task ServerTask(CancellationToken cancellationToken) + { + using Socket server = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); + server.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true); + server.Bind(Program.Constants.ServerEndPoint); + + byte[] transmissionBuffer = new byte[PacketSize]; + + EndPoint remoteEndPoint = new IPEndPoint(IPAddress.Any, 0); + + ServerReadyEvent.Set(); + + while (!cancellationToken.IsCancellationRequested) + { + server.ReceiveFrom(transmissionBuffer, ref remoteEndPoint); + + server.SendTo(transmissionBuffer, remoteEndPoint); + } + + server.Close(); + + return Task.CompletedTask; + } + + /// <inheritdoc /> + public async Task RunAsync() + { + if (PacketCount > 10_000) + { + Console.WriteLine($"{PacketCount} packets will be sent per client. This could take a long time (maybe more than a minute)!"); + } + + EndPoint defaultRemoteEndPoint = new IPEndPoint(IPAddress.Any, 0); + + BenchmarkHelper benchmarkHelper = new BenchmarkHelper(); + + byte[] sendBuffer = new byte[PacketSize]; + byte[] receiveBuffer = new byte[PacketSize]; + + Socket rawSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); + rawSocket.Bind(Program.Constants.ClientEndPoint); + + using RawDatagramNetworkWriter writer = new RawDatagramNetworkWriter(ref rawSocket, defaultRemoteEndPoint, PacketSize); + + using CancellationTokenSource serverCts = new CancellationTokenSource(); + Task serverTask = Task.Factory.StartNew(state => ServerTask((CancellationToken) state), serverCts.Token, TaskCreationOptions.LongRunning); + + benchmarkHelper.ResetStopwatch(); + + ServerReadyEvent.Wait(); + + for (int i = 0; i < PacketCount; i++) + { + byte[] packetBuffer = Program.Constants.ServerEncoding.GetBytes($"[Client 0] Hello World! (Packet {i})"); + packetBuffer.CopyTo(sendBuffer, 0); + + benchmarkHelper.StartStopwatch(); + int sendResult = await writer.WriteAsync(Program.Constants.ServerEndPoint, sendBuffer); + + int receiveResult = await writer.ReadAsync(Program.Constants.ServerEndPoint, receiveBuffer); + benchmarkHelper.StopStopwatch(); + + benchmarkHelper.SnapshotRttStats(); + } + + benchmarkHelper.PrintBandwidthStats(0, PacketCount, PacketSize); + benchmarkHelper.PrintRttStats(0); + + serverCts.Cancel(); + try + { + serverTask.Dispose(); + } + catch (Exception) + { + // ignored + } + + rawSocket.Close(); + rawSocket.Dispose(); + } + } +} +\ No newline at end of file diff --git a/NetSharp/NetSharp.Benchmarks/Benchmarks/Datagram Network Connection Benchmarks/RawDatagramNetworkWriterSyncBenchmark.cs b/NetSharp/NetSharp.Benchmarks/Benchmarks/Datagram Network Connection Benchmarks/RawDatagramNetworkWriterSyncBenchmark.cs @@ -0,0 +1,97 @@ +using System; +using System.Net; +using System.Net.Sockets; +using System.Threading; +using System.Threading.Tasks; + +using NetSharp.Raw.Datagram; + +namespace NetSharp.Benchmarks.Benchmarks.Datagram_Network_Connection_Benchmarks +{ + internal class RawDatagramNetworkWriterSyncBenchmark : INetSharpBenchmark + { + private const int PacketSize = 8192, PacketCount = 1_000_000; + private static readonly ManualResetEventSlim ServerReadyEvent = new ManualResetEventSlim(false); + + /// <inheritdoc /> + public string Name { get; } = "Raw Datagram Network Writer Benchmark (Synchronous)"; + + private static Task ServerTask(CancellationToken cancellationToken) + { + using Socket server = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); + server.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true); + server.Bind(Program.Constants.ServerEndPoint); + + byte[] transmissionBuffer = new byte[PacketSize]; + + EndPoint remoteEndPoint = new IPEndPoint(IPAddress.Any, 0); + + ServerReadyEvent.Set(); + + while (!cancellationToken.IsCancellationRequested) + { + int received = server.ReceiveFrom(transmissionBuffer, ref remoteEndPoint); + + int sent = server.SendTo(transmissionBuffer, remoteEndPoint); + } + + server.Close(); + + return Task.CompletedTask; + } + + /// <inheritdoc /> + public Task RunAsync() + { + if (PacketCount > 10_000) + { + Console.WriteLine($"{PacketCount} packets will be sent per client. This could take a long time (maybe more than a minute)!"); + } + + EndPoint defaultRemoteEndPoint = new IPEndPoint(IPAddress.Any, 0); + + BenchmarkHelper benchmarkHelper = new BenchmarkHelper(); + + byte[] sendBuffer = new byte[PacketSize]; + byte[] receiveBuffer = new byte[PacketSize]; + + EndPoint remoteEndPoint = Program.Constants.ServerEndPoint; + + Socket rawSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); + rawSocket.Bind(Program.Constants.ClientEndPoint); + + using RawDatagramNetworkWriter writer = new RawDatagramNetworkWriter(ref rawSocket, defaultRemoteEndPoint, PacketSize); + + using CancellationTokenSource serverCts = new CancellationTokenSource(); + Task serverTask = Task.Factory.StartNew(state => ServerTask((CancellationToken) state), serverCts.Token, TaskCreationOptions.LongRunning); + + ServerReadyEvent.Wait(); + + benchmarkHelper.ResetStopwatch(); + + for (int i = 0; i < PacketCount; i++) + { + byte[] packetBuffer = Program.Constants.ServerEncoding.GetBytes($"[Client 0] Hello World! (Packet {i})"); + packetBuffer.CopyTo(sendBuffer, 0); + + benchmarkHelper.StartStopwatch(); + int sendResult = writer.Write(Program.Constants.ServerEndPoint, sendBuffer); + + int receiveResult = writer.Read(ref remoteEndPoint, receiveBuffer); + benchmarkHelper.StopStopwatch(); + + benchmarkHelper.SnapshotRttStats(); + } + + benchmarkHelper.PrintBandwidthStats(0, PacketCount, PacketSize); + benchmarkHelper.PrintRttStats(0); + + serverCts.Cancel(); + + rawSocket.Close(); + rawSocket.Dispose(); + + return Task.CompletedTask; + } + } +} +\ No newline at end of file diff --git a/NetSharp/NetSharp.Benchmarks/Benchmarks/Stream Network Connection Benchmarks/RawStreamNetworkReaderMultiClientBenchmark.cs b/NetSharp/NetSharp.Benchmarks/Benchmarks/Stream Network Connection Benchmarks/RawStreamNetworkReaderMultiClientBenchmark.cs @@ -0,0 +1,143 @@ +using System; +using System.Linq; +using System.Net; +using System.Net.Sockets; +using System.Threading; +using System.Threading.Tasks; + +using NetSharp.Raw.Stream; + +namespace NetSharp.Benchmarks.Benchmarks.Stream_Network_Connection_Benchmarks +{ + internal class RawStreamNetworkReaderMultiClientBenchmark : INetSharpBenchmark + { + private const int PacketSize = 8192, PacketCount = 1_000_000, ClientCount = 8; + private static readonly ManualResetEventSlim ServerReadyEvent = new ManualResetEventSlim(false); + private double[] ClientBandwidths; + + /// <inheritdoc /> + public string Name { get; } = "Raw Stream Network Reader (Multiple Clients) Benchmark"; + + private static bool RequestHandler(EndPoint remoteEndPoint, in ReadOnlyMemory<byte> requestBuffer, int receivedRequestBytes, + in Memory<byte> responseBuffer) + { + requestBuffer.CopyTo(responseBuffer); + + return true; + } + + private Task BenchmarkClientTask(object idObj) + { + int id = (int) idObj; + + BenchmarkHelper benchmarkHelper = new BenchmarkHelper(); + + byte[] sendBuffer = new byte[PacketSize + RawStreamPacketHeader.TotalSize]; + byte[] receiveBuffer = new byte[PacketSize + RawStreamPacketHeader.TotalSize]; + byte[] packetBuffer = new byte[PacketSize]; + + EndPoint remoteEndPoint = Program.Constants.ServerEndPoint; + + using Socket clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); + clientSocket.Bind(Program.Constants.ClientEndPoint); + + ServerReadyEvent.Wait(); + clientSocket.Connect(Program.Constants.ServerEndPoint); + + lock (typeof(Console)) + { + Console.WriteLine($"[Client {id}] Starting client; sending messages to {remoteEndPoint}"); + } + + benchmarkHelper.ResetStopwatch(); + + for (int i = 0; i < PacketCount; i++) + { + Program.Constants.ServerEncoding.GetBytes($"[Client {id}] Hello World! (Packet {i})").CopyTo(packetBuffer, 0); + + RawStreamPacketHeader streamPacketHeader = new RawStreamPacketHeader(PacketSize); + RawStreamPacket.Serialise(sendBuffer, in streamPacketHeader, packetBuffer); + + benchmarkHelper.StartStopwatch(); + + int totalSent = 0; + do + { + totalSent += clientSocket.Send(sendBuffer, totalSent, sendBuffer.Length - totalSent, + SocketFlags.None); + } while (totalSent != 0 && totalSent < sendBuffer.Length); + + if (totalSent == 0) + { + break; + } + + int totalReceived = 0; + do + { + totalReceived += clientSocket.Receive(receiveBuffer, totalReceived, receiveBuffer.Length - totalReceived, + SocketFlags.None); + } while (totalReceived != 0 && totalReceived < receiveBuffer.Length); + + if (totalReceived == 0) + { + break; + } + + benchmarkHelper.StopStopwatch(); + + benchmarkHelper.SnapshotRttStats(); + } + + clientSocket.Disconnect(true); + clientSocket.Close(); + + lock (typeof(Console)) + { + benchmarkHelper.PrintBandwidthStats(id, PacketCount, PacketSize); + benchmarkHelper.PrintRttStats(id); + } + + ClientBandwidths[id] = benchmarkHelper.CalcBandwidth(PacketCount, PacketSize); + + return Task.CompletedTask; + } + + /// <inheritdoc /> + public async Task RunAsync() + { + if (PacketCount > 10_000) + { + Console.WriteLine($"{PacketCount} packets will be sent per client. This could take a long time (maybe more than a minute)!"); + } + + 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); + } + + EndPoint defaultEndPoint = new IPEndPoint(IPAddress.Any, 0); + + Socket rawSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); + rawSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true); + rawSocket.Bind(Program.Constants.ServerEndPoint); + rawSocket.Listen(ClientCount); + + using RawStreamNetworkReader reader = new RawStreamNetworkReader(ref rawSocket, RequestHandler, defaultEndPoint, PacketSize); + reader.Start(ClientCount); + + ServerReadyEvent.Set(); + + await Task.WhenAll(clientTasks); + + Console.WriteLine($"Total estimated bandwidth: {ClientBandwidths.Sum():F3}"); + + reader.Shutdown(); + + rawSocket.Close(); + rawSocket.Dispose(); + } + } +} +\ No newline at end of file diff --git a/NetSharp/NetSharp.Benchmarks/Benchmarks/Stream Network Connection Benchmarks/RawStreamNetworkReaderSingleClientBenchmark.cs b/NetSharp/NetSharp.Benchmarks/Benchmarks/Stream Network Connection Benchmarks/RawStreamNetworkReaderSingleClientBenchmark.cs @@ -0,0 +1,138 @@ +using System; +using System.Net; +using System.Net.Sockets; +using System.Threading; +using System.Threading.Tasks; + +using NetSharp.Raw.Stream; + +namespace NetSharp.Benchmarks.Benchmarks.Stream_Network_Connection_Benchmarks +{ + internal class RawStreamNetworkReaderSingleClientBenchmark : INetSharpBenchmark + { + private const int PacketSize = 8192, PacketCount = 1_000_000; + private static readonly ManualResetEventSlim ServerReadyEvent = new ManualResetEventSlim(false); + private double[] ClientBandwidths; + + /// <inheritdoc /> + public string Name { get; } = "Raw Stream Network Reader (Single Client) Benchmark"; + + private static bool RequestHandler(EndPoint remoteEndPoint, in ReadOnlyMemory<byte> requestBuffer, int receivedRequestBytes, + in Memory<byte> responseBuffer) + { + requestBuffer.CopyTo(responseBuffer); + + return true; + } + + private Task BenchmarkClientTask(object idObj) + { + int id = (int) idObj; + + BenchmarkHelper benchmarkHelper = new BenchmarkHelper(); + + byte[] sendBuffer = new byte[PacketSize + RawStreamPacketHeader.TotalSize]; + byte[] receiveBuffer = new byte[PacketSize + RawStreamPacketHeader.TotalSize]; + byte[] packetBuffer = new byte[PacketSize]; + + EndPoint remoteEndPoint = Program.Constants.ServerEndPoint; + + using Socket clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); + clientSocket.Bind(Program.Constants.ClientEndPoint); + + ServerReadyEvent.Wait(); + clientSocket.Connect(Program.Constants.ServerEndPoint); + + lock (typeof(Console)) + { + Console.WriteLine($"[Client {id}] Starting client; sending messages to {remoteEndPoint}"); + } + + benchmarkHelper.ResetStopwatch(); + + for (int i = 0; i < PacketCount; i++) + { + Program.Constants.ServerEncoding.GetBytes($"[Client {id}] Hello World! (Packet {i})").CopyTo(packetBuffer, 0); + + RawStreamPacketHeader streamPacketHeader = new RawStreamPacketHeader(PacketSize); + RawStreamPacket.Serialise(sendBuffer, in streamPacketHeader, packetBuffer); + + benchmarkHelper.StartStopwatch(); + + int totalSent = 0; + do + { + totalSent += clientSocket.Send(sendBuffer, totalSent, sendBuffer.Length - totalSent, + SocketFlags.None); + } while (totalSent != 0 && totalSent < sendBuffer.Length); + + if (totalSent == 0) + { + break; + } + + int totalReceived = 0; + do + { + totalReceived += clientSocket.Receive(receiveBuffer, totalReceived, receiveBuffer.Length - totalReceived, + SocketFlags.None); + } while (totalReceived != 0 && totalReceived < receiveBuffer.Length); + + if (totalReceived == 0) + { + break; + } + + benchmarkHelper.StopStopwatch(); + + benchmarkHelper.SnapshotRttStats(); + } + + clientSocket.Disconnect(true); + clientSocket.Close(); + + lock (typeof(Console)) + { + benchmarkHelper.PrintBandwidthStats(id, PacketCount, PacketSize); + benchmarkHelper.PrintRttStats(id); + } + + ClientBandwidths[id] = benchmarkHelper.CalcBandwidth(PacketCount, PacketSize); + + return Task.CompletedTask; + } + + /// <inheritdoc /> + public async Task RunAsync() + { + if (PacketCount > 10_000) + { + Console.WriteLine($"{PacketCount} packets will be sent per client. This could take a long time (maybe more than a minute)!"); + } + + ClientBandwidths = new double[1]; + Task[] clientTasks = new Task[] { Task.Factory.StartNew(BenchmarkClientTask, 0, TaskCreationOptions.LongRunning) }; + + EndPoint defaultEndPoint = new IPEndPoint(IPAddress.Any, 0); + + Socket rawSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); + rawSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true); + rawSocket.Bind(Program.Constants.ServerEndPoint); + rawSocket.Listen(1); + + using RawStreamNetworkReader reader = new RawStreamNetworkReader(ref rawSocket, RequestHandler, defaultEndPoint, PacketSize); + reader.Start(1); + + ServerReadyEvent.Set(); + + await clientTasks[0]; + + Console.WriteLine($"Total estimated bandwidth: {ClientBandwidths[0]:F3}"); + + reader.Shutdown(); + + rawSocket.Close(); + rawSocket.Dispose(); + } + } +} +\ No newline at end of file diff --git a/NetSharp/NetSharp.Benchmarks/Benchmarks/Stream Network Connection Benchmarks/RawStreamNetworkWriterAsyncBenchmark.cs b/NetSharp/NetSharp.Benchmarks/Benchmarks/Stream Network Connection Benchmarks/RawStreamNetworkWriterAsyncBenchmark.cs @@ -0,0 +1,128 @@ +using System; +using System.Net; +using System.Net.Sockets; +using System.Threading; +using System.Threading.Tasks; + +using NetSharp.Raw.Stream; + +namespace NetSharp.Benchmarks.Benchmarks.Stream_Network_Connection_Benchmarks +{ + internal class RawStreamNetworkWriterAsyncBenchmark : INetSharpBenchmark + { + private const int PacketSize = 8192, PacketCount = 1_000_000; + private static readonly ManualResetEventSlim ServerReadyEvent = new ManualResetEventSlim(false); + + /// <inheritdoc /> + public string Name { get; } = "Raw Stream Network Writer Benchmark (Asynchronous)"; + + private static Task ServerTask(CancellationToken cancellationToken) + { + using Socket server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); + server.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true); + server.Bind(Program.Constants.ServerEndPoint); + + RawStreamPacketHeader archetypalHeader = new RawStreamPacketHeader(PacketSize); + byte[] transmissionBuffer = new byte[RawStreamPacket.TotalPacketSize(in archetypalHeader)]; + + server.Listen(1); + + ServerReadyEvent.Set(); + + Socket clientSocket = server.Accept(); + + while (!cancellationToken.IsCancellationRequested) + { + int expectedBytes = transmissionBuffer.Length; + + int receivedBytes = 0; + do + { + receivedBytes += clientSocket.Receive(transmissionBuffer, receivedBytes, expectedBytes - receivedBytes, SocketFlags.None); + } while (receivedBytes != 0 && receivedBytes < expectedBytes); + + if (receivedBytes == 0) + { + break; + } + + int sentBytes = 0; + do + { + sentBytes += clientSocket.Send(transmissionBuffer, sentBytes, expectedBytes - sentBytes, SocketFlags.None); + } while (sentBytes != 0 && sentBytes < expectedBytes); + + if (sentBytes == 0) + { + break; + } + } + + server.Shutdown(SocketShutdown.Both); + server.Close(); + + return Task.CompletedTask; + } + + /// <inheritdoc /> + public async Task RunAsync() + { + if (PacketCount > 10_000) + { + Console.WriteLine($"{PacketCount} packets will be sent per client. This could take a long time (maybe more than a minute)!"); + } + + EndPoint defaultRemoteEndPoint = new IPEndPoint(IPAddress.Any, 0); + + BenchmarkHelper benchmarkHelper = new BenchmarkHelper(); + + byte[] sendBuffer = new byte[PacketSize]; + byte[] receiveBuffer = new byte[PacketSize]; + + Socket rawSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); + rawSocket.Bind(Program.Constants.ClientEndPoint); + + using RawStreamNetworkWriter writer = new RawStreamNetworkWriter(ref rawSocket, defaultRemoteEndPoint, PacketSize); + + using CancellationTokenSource serverCts = new CancellationTokenSource(); + Task serverTask = Task.Factory.StartNew(state => ServerTask((CancellationToken) state), serverCts.Token, TaskCreationOptions.LongRunning); + + ServerReadyEvent.Wait(); + rawSocket.Connect(Program.Constants.ServerEndPoint); + + benchmarkHelper.ResetStopwatch(); + + for (int i = 0; i < PacketCount; i++) + { + byte[] packetBuffer = Program.Constants.ServerEncoding.GetBytes($"[Client 0] Hello World! (Packet {i})"); + packetBuffer.CopyTo(sendBuffer, 0); + + benchmarkHelper.StartStopwatch(); + int sendResult = await writer.WriteAsync(Program.Constants.ServerEndPoint, sendBuffer); + + int receiveResult = await writer.ReadAsync(Program.Constants.ServerEndPoint, receiveBuffer); + benchmarkHelper.StopStopwatch(); + + benchmarkHelper.SnapshotRttStats(); + } + + benchmarkHelper.PrintBandwidthStats(0, PacketCount, PacketSize); + benchmarkHelper.PrintRttStats(0); + + serverCts.Cancel(); + try + { + serverTask.Dispose(); + } + catch (Exception) + { + // ignored + } + + rawSocket.Disconnect(false); + rawSocket.Shutdown(SocketShutdown.Both); + rawSocket.Close(); + rawSocket.Dispose(); + } + } +} +\ No newline at end of file diff --git a/NetSharp/NetSharp.Benchmarks/Benchmarks/Stream Network Connection Benchmarks/RawStreamNetworkWriterSyncBenchmark.cs b/NetSharp/NetSharp.Benchmarks/Benchmarks/Stream Network Connection Benchmarks/RawStreamNetworkWriterSyncBenchmark.cs @@ -0,0 +1,133 @@ +using System; +using System.Net; +using System.Net.Sockets; +using System.Threading; +using System.Threading.Tasks; + +using NetSharp.Raw.Stream; + +namespace NetSharp.Benchmarks.Benchmarks.Stream_Network_Connection_Benchmarks +{ + internal class RawStreamNetworkWriterSyncBenchmark : INetSharpBenchmark + { + private const int PacketSize = 8192, PacketCount = 1_000_000; + private static readonly ManualResetEventSlim ServerReadyEvent = new ManualResetEventSlim(false); + + /// <inheritdoc /> + public string Name { get; } = "Raw Stream Network Writer Benchmark (Synchronous)"; + + private static Task ServerTask(CancellationToken cancellationToken) + { + using Socket server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); + server.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true); + server.Bind(Program.Constants.ServerEndPoint); + + // all the headers should have the same packet size, so will fit in the transmission buffer + RawStreamPacketHeader archetypalHeader = new RawStreamPacketHeader(PacketSize); + byte[] transmissionBuffer = new byte[RawStreamPacket.TotalPacketSize(in archetypalHeader)]; + + server.Listen(1); + + ServerReadyEvent.Set(); + + Socket clientSocket = server.Accept(); + + while (!cancellationToken.IsCancellationRequested) + { + int expectedBytes = transmissionBuffer.Length; + + int receivedBytes = 0; + do + { + receivedBytes += clientSocket.Receive(transmissionBuffer, receivedBytes, expectedBytes - receivedBytes, SocketFlags.None); + } while (receivedBytes < expectedBytes && receivedBytes > 0); + + if (receivedBytes == 0) + { + break; + } + + int sentBytes = 0; + do + { + sentBytes += clientSocket.Send(transmissionBuffer, sentBytes, expectedBytes - sentBytes, SocketFlags.None); + } while (sentBytes < expectedBytes && sentBytes > 0); + + if (sentBytes == 0) + { + break; + } + } + + server.Shutdown(SocketShutdown.Both); + server.Close(); + + return Task.CompletedTask; + } + + /// <inheritdoc /> + public Task RunAsync() + { + if (PacketCount > 10_000) + { + Console.WriteLine($"{PacketCount} packets will be sent per client. This could take a long time (maybe more than a minute)!"); + } + + EndPoint defaultRemoteEndPoint = new IPEndPoint(IPAddress.Any, 0); + + BenchmarkHelper benchmarkHelper = new BenchmarkHelper(); + + byte[] sendBuffer = new byte[PacketSize]; + byte[] receiveBuffer = new byte[PacketSize]; + + EndPoint remoteEndPoint = Program.Constants.ServerEndPoint; + + Socket rawSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); + rawSocket.Bind(Program.Constants.ClientEndPoint); + + using RawStreamNetworkWriter writer = new RawStreamNetworkWriter(ref rawSocket, defaultRemoteEndPoint, PacketSize); + + using CancellationTokenSource serverCts = new CancellationTokenSource(); + Task serverTask = Task.Factory.StartNew(state => ServerTask((CancellationToken) state), serverCts.Token, TaskCreationOptions.LongRunning); + + ServerReadyEvent.Wait(); + rawSocket.Connect(Program.Constants.ServerEndPoint); + + benchmarkHelper.ResetStopwatch(); + + for (int i = 0; i < PacketCount; i++) + { + byte[] packetBuffer = Program.Constants.ServerEncoding.GetBytes($"[Client 0] Hello World! (Packet {i})"); + packetBuffer.CopyTo(sendBuffer, 0); + + benchmarkHelper.StartStopwatch(); + int sendResult = writer.Write(Program.Constants.ServerEndPoint, sendBuffer); + + int receiveResult = writer.Read(ref remoteEndPoint, receiveBuffer); + benchmarkHelper.StopStopwatch(); + + benchmarkHelper.SnapshotRttStats(); + } + + benchmarkHelper.PrintBandwidthStats(0, PacketCount, PacketSize); + benchmarkHelper.PrintRttStats(0); + + serverCts.Cancel(); + try + { + serverTask.Dispose(); + } + catch (Exception) + { + // ignored + } + + rawSocket.Disconnect(false); + rawSocket.Shutdown(SocketShutdown.Both); + rawSocket.Close(); + rawSocket.Dispose(); + + return Task.CompletedTask; + } + } +} +\ No newline at end of file diff --git a/NetSharp/NetSharp.Benchmarks/Benchmarks/Stream Network Connection Benchmarks/StreamNetworkReaderBenchmark.cs b/NetSharp/NetSharp.Benchmarks/Benchmarks/Stream Network Connection Benchmarks/StreamNetworkReaderBenchmark.cs @@ -1,138 +0,0 @@ -using System; -using System.Linq; -using System.Net; -using System.Net.Sockets; -using System.Threading; -using System.Threading.Tasks; - -using NetSharp.Packets; -using NetSharp.Raw.Stream; - -namespace NetSharp.Benchmarks.Benchmarks.Stream_Network_Connection_Benchmarks -{ - internal class StreamNetworkReaderBenchmark : INetSharpBenchmark - { - private const int PacketSize = 8192, PacketCount = 1_000_000, ClientCount = 12; - private static readonly ManualResetEventSlim ServerReadyEvent = new ManualResetEventSlim(); - private double[] ClientBandwidths; - - /// <inheritdoc /> - public string Name { get; } = "Raw Stream Network Reader Benchmark"; - - private static bool RequestHandler(EndPoint remoteEndPoint, in ReadOnlyMemory<byte> requestBuffer, int receivedRequestBytes, - in Memory<byte> responseBuffer) - { - requestBuffer.CopyTo(responseBuffer); - - return true; - } - - private Task BenchmarkClientTask(object idObj) - { - int id = (int) idObj; - - BenchmarkHelper benchmarkHelper = new BenchmarkHelper(); - - Socket clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); - clientSocket.Bind(Program.Constants.ClientEndPoint); - - ServerReadyEvent.Wait(); - clientSocket.Connect(Program.Constants.ServerEndPoint); - - byte[] sendBuffer = new byte[PacketSize + RawStreamPacketHeader.TotalSize]; - byte[] receiveBuffer = new byte[PacketSize + RawStreamPacketHeader.TotalSize]; - byte[] packetBuffer = new byte[PacketSize]; - - EndPoint remoteEndPoint = Program.Constants.ServerEndPoint; - - lock (typeof(Console)) - { - Console.WriteLine($"[Client {id}] Starting client; sending messages to {remoteEndPoint}"); - } - - for (int i = 0; i < PacketCount; i++) - { - Program.Constants.ServerEncoding.GetBytes($"[Client {id}] Hello World! (Packet {i})").CopyTo(packetBuffer, 0); - - RawStreamPacketHeader streamPacketHeader = new RawStreamPacketHeader(PacketSize); - RawStreamPacket.Serialise(sendBuffer, in streamPacketHeader, packetBuffer); - - benchmarkHelper.StartStopwatch(); - - int totalSent = 0; - do - { - totalSent += clientSocket.Send(sendBuffer, totalSent, sendBuffer.Length - totalSent, - SocketFlags.None); - } while (totalSent != 0 && totalSent < sendBuffer.Length); - - if (totalSent == 0) - { - break; - } - - int totalReceived = 0; - do - { - totalReceived += clientSocket.Receive(receiveBuffer, totalReceived, receiveBuffer.Length - totalReceived, - SocketFlags.None); - } while (totalReceived != 0 && totalReceived < receiveBuffer.Length); - - if (totalReceived == 0) - { - break; - } - - benchmarkHelper.StopStopwatch(); - - benchmarkHelper.SnapshotRttStats(); - } - - clientSocket.Disconnect(true); - clientSocket.Close(); - - benchmarkHelper.PrintBandwidthStats(id, PacketCount, PacketSize); - benchmarkHelper.PrintRttStats(id); - - ClientBandwidths[id] = benchmarkHelper.CalcBandwidth(PacketCount, PacketSize); - - return Task.CompletedTask; - } - - /// <inheritdoc /> - public async Task RunAsync() - { - if (PacketCount > 10_000) - { - Console.WriteLine($"{PacketCount} packets will be sent per client. This could take a long time (maybe more than a minute)!"); - } - - 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); - } - - EndPoint defaultEndPoint = new IPEndPoint(IPAddress.Any, 0); - - Socket rawSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); - rawSocket.Bind(Program.Constants.ServerEndPoint); - rawSocket.Listen(ClientCount); - - using RawStreamNetworkReader reader = new RawStreamNetworkReader(ref rawSocket, RequestHandler, defaultEndPoint, PacketSize); - reader.Start(ClientCount); - - ServerReadyEvent.Set(); - - await Task.WhenAll(clientTasks); - - Console.WriteLine($"Total estimated bandwidth: {ClientBandwidths.Sum():F3}"); - - reader.Shutdown(); - - rawSocket.Close(); - rawSocket.Dispose(); - } - } -} -\ No newline at end of file diff --git a/NetSharp/NetSharp.Benchmarks/Benchmarks/Stream Network Connection Benchmarks/StreamNetworkWriterAsyncBenchmark.cs b/NetSharp/NetSharp.Benchmarks/Benchmarks/Stream Network Connection Benchmarks/StreamNetworkWriterAsyncBenchmark.cs @@ -1,125 +0,0 @@ -using System; -using System.Net; -using System.Net.Sockets; -using System.Threading; -using System.Threading.Tasks; - -using NetSharp.Packets; -using NetSharp.Raw.Stream; - -namespace NetSharp.Benchmarks.Benchmarks.Stream_Network_Connection_Benchmarks -{ - internal class StreamNetworkWriterAsyncBenchmark : INetSharpBenchmark - { - private const int PacketSize = 8192, PacketCount = 1_000_000; - private static readonly ManualResetEventSlim ServerReadyEvent = new ManualResetEventSlim(); - - /// <inheritdoc /> - public string Name { get; } = "Raw Stream Network Writer Benchmark (Asynchronous)"; - - private static Task ServerTask(CancellationToken cancellationToken) - { - using Socket server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); - - server.Bind(Program.Constants.ServerEndPoint); - ServerReadyEvent.Set(); - - RawStreamPacketHeader archetypalHeader = new RawStreamPacketHeader(PacketSize); - byte[] transmissionBuffer = new byte[RawStreamPacket.TotalPacketSize(in archetypalHeader)]; - - server.Listen(1); - Socket clientSocket = server.Accept(); - - while (!cancellationToken.IsCancellationRequested) - { - int expectedBytes = transmissionBuffer.Length; - - int receivedBytes = 0; - do - { - receivedBytes += clientSocket.Receive(transmissionBuffer, receivedBytes, expectedBytes - receivedBytes, SocketFlags.None); - } while (receivedBytes != 0 && receivedBytes < expectedBytes); - - if (receivedBytes == 0) - { - break; - } - - int sentBytes = 0; - do - { - sentBytes += clientSocket.Send(transmissionBuffer, sentBytes, expectedBytes - sentBytes, SocketFlags.None); - } while (sentBytes != 0 && sentBytes < expectedBytes); - - if (sentBytes == 0) - { - break; - } - } - - server.Shutdown(SocketShutdown.Both); - server.Close(); - - return Task.CompletedTask; - } - - /// <inheritdoc /> - public async Task RunAsync() - { - if (PacketCount > 10_000) - { - Console.WriteLine($"{PacketCount} packets will be sent per client. This could take a long time (maybe more than a minute)!"); - } - - EndPoint defaultRemoteEndPoint = new IPEndPoint(IPAddress.Any, 0); - - Socket rawSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); - rawSocket.Bind(Program.Constants.ClientEndPoint); - - using RawStreamNetworkWriter writer = new RawStreamNetworkWriter(ref rawSocket, defaultRemoteEndPoint, PacketSize); - - using CancellationTokenSource serverCts = new CancellationTokenSource(); - Task serverTask = Task.Factory.StartNew(state => ServerTask((CancellationToken) state), serverCts.Token, TaskCreationOptions.LongRunning); - - ServerReadyEvent.Wait(); - rawSocket.Connect(Program.Constants.ServerEndPoint); - - BenchmarkHelper benchmarkHelper = new BenchmarkHelper(); - - byte[] sendBuffer = new byte[PacketSize]; - byte[] receiveBuffer = new byte[PacketSize]; - - for (int i = 0; i < PacketCount; i++) - { - byte[] packetBuffer = Program.Constants.ServerEncoding.GetBytes($"[Client 0] Hello World! (Packet {i})"); - packetBuffer.CopyTo(sendBuffer, 0); - - benchmarkHelper.StartStopwatch(); - int sendResult = await writer.WriteAsync(Program.Constants.ServerEndPoint, sendBuffer); - - int receiveResult = await writer.ReadAsync(Program.Constants.ServerEndPoint, receiveBuffer); - benchmarkHelper.StopStopwatch(); - - benchmarkHelper.SnapshotRttStats(); - } - - benchmarkHelper.PrintBandwidthStats(0, PacketCount, PacketSize); - benchmarkHelper.PrintRttStats(0); - - serverCts.Cancel(); - try - { - serverTask.Dispose(); - } - catch (Exception) - { - // ignored - } - - rawSocket.Disconnect(false); - rawSocket.Shutdown(SocketShutdown.Both); - rawSocket.Close(); - rawSocket.Dispose(); - } - } -} -\ No newline at end of file diff --git a/NetSharp/NetSharp.Benchmarks/Benchmarks/Stream Network Connection Benchmarks/StreamNetworkWriterSyncBenchmark.cs b/NetSharp/NetSharp.Benchmarks/Benchmarks/Stream Network Connection Benchmarks/StreamNetworkWriterSyncBenchmark.cs @@ -1,130 +0,0 @@ -using System; -using System.Net; -using System.Net.Sockets; -using System.Threading; -using System.Threading.Tasks; - -using NetSharp.Packets; -using NetSharp.Raw.Stream; - -namespace NetSharp.Benchmarks.Benchmarks.Stream_Network_Connection_Benchmarks -{ - internal class StreamNetworkWriterSyncBenchmark : INetSharpBenchmark - { - private const int PacketSize = 8192, PacketCount = 1_000_000; - private static readonly ManualResetEventSlim ServerReadyEvent = new ManualResetEventSlim(); - - /// <inheritdoc /> - public string Name { get; } = "Raw Stream Network Writer Benchmark (Synchronous)"; - - private static Task ServerTask(CancellationToken cancellationToken) - { - using Socket server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); - - server.Bind(Program.Constants.ServerEndPoint); - ServerReadyEvent.Set(); - - // all the headers should have the same packet size, so will fit in the transmission buffer - RawStreamPacketHeader archetypalHeader = new RawStreamPacketHeader(PacketSize); - byte[] transmissionBuffer = new byte[RawStreamPacket.TotalPacketSize(in archetypalHeader)]; - - server.Listen(1); - Socket clientSocket = server.Accept(); - - while (!cancellationToken.IsCancellationRequested) - { - int expectedBytes = transmissionBuffer.Length; - - int receivedBytes = 0; - do - { - receivedBytes += clientSocket.Receive(transmissionBuffer, receivedBytes, expectedBytes - receivedBytes, SocketFlags.None); - } while (receivedBytes < expectedBytes && receivedBytes > 0); - - if (receivedBytes == 0) - { - break; - } - - int sentBytes = 0; - do - { - sentBytes += clientSocket.Send(transmissionBuffer, sentBytes, expectedBytes - sentBytes, SocketFlags.None); - } while (sentBytes < expectedBytes && sentBytes > 0); - - if (sentBytes == 0) - { - break; - } - } - - server.Shutdown(SocketShutdown.Both); - server.Close(); - - return Task.CompletedTask; - } - - /// <inheritdoc /> - public Task RunAsync() - { - if (PacketCount > 10_000) - { - Console.WriteLine($"{PacketCount} packets will be sent per client. This could take a long time (maybe more than a minute)!"); - } - - EndPoint defaultRemoteEndPoint = new IPEndPoint(IPAddress.Any, 0); - - Socket rawSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); - rawSocket.Bind(Program.Constants.ClientEndPoint); - - using RawStreamNetworkWriter writer = new RawStreamNetworkWriter(ref rawSocket, defaultRemoteEndPoint, PacketSize); - - using CancellationTokenSource serverCts = new CancellationTokenSource(); - Task serverTask = Task.Factory.StartNew(state => ServerTask((CancellationToken) state), serverCts.Token, TaskCreationOptions.LongRunning); - - ServerReadyEvent.Wait(); - rawSocket.Connect(Program.Constants.ServerEndPoint); - - BenchmarkHelper benchmarkHelper = new BenchmarkHelper(); - - byte[] sendBuffer = new byte[PacketSize]; - byte[] receiveBuffer = new byte[PacketSize]; - - EndPoint remoteEndPoint = Program.Constants.ServerEndPoint; - - for (int i = 0; i < PacketCount; i++) - { - byte[] packetBuffer = Program.Constants.ServerEncoding.GetBytes($"[Client 0] Hello World! (Packet {i})"); - packetBuffer.CopyTo(sendBuffer, 0); - - benchmarkHelper.StartStopwatch(); - int sendResult = writer.Write(Program.Constants.ServerEndPoint, sendBuffer); - - int receiveResult = writer.Read(ref remoteEndPoint, receiveBuffer); - benchmarkHelper.StopStopwatch(); - - benchmarkHelper.SnapshotRttStats(); - } - - benchmarkHelper.PrintBandwidthStats(0, PacketCount, PacketSize); - benchmarkHelper.PrintRttStats(0); - - serverCts.Cancel(); - try - { - serverTask.Dispose(); - } - catch (Exception) - { - // ignored - } - - rawSocket.Disconnect(false); - rawSocket.Shutdown(SocketShutdown.Both); - rawSocket.Close(); - rawSocket.Dispose(); - - return Task.CompletedTask; - } - } -} -\ No newline at end of file diff --git a/NetSharp/NetSharp.Benchmarks/Program.cs b/NetSharp/NetSharp.Benchmarks/Program.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Net; using System.Reflection; using System.Resources; @@ -19,25 +20,21 @@ namespace NetSharp.Benchmarks foreach (Type type in Assembly.GetCallingAssembly().GetTypes()) { - if (!type.IsClass && !type.IsValueType) + if (type.IsAbstract) { continue; } Type[] interfaces = type.GetInterfaces(); - object instance = Activator.CreateInstance(type); - - if (type.GetInterface(nameof(INetSharpBenchmark)) == typeof(INetSharpBenchmark)) + if (interfaces.Contains(typeof(INetSharpBenchmark))) { - Benchmarks.Add((INetSharpBenchmark) instance); + Benchmarks.Add((INetSharpBenchmark) Activator.CreateInstance(type)); } } } private static void Main() { - RunAllBenchmarks(); - while (true) { GC.Collect(); @@ -48,20 +45,31 @@ namespace NetSharp.Benchmarks private static void PickBenchmark() { - Console.WriteLine("Available Examples:"); - for (int i = 0; i < Benchmarks.Count; i++) - { - Console.WriteLine($"\t{i:D2} - {Benchmarks[i].Name}"); - } + const string allBenchmarkIdentifier = "XX"; while (true) { + Console.WriteLine("Available Examples:"); + for (int i = 0; i < Benchmarks.Count; i++) + { + Console.WriteLine($"\t{i:D2} - {Benchmarks[i].Name}"); + } + Console.WriteLine($"\t{allBenchmarkIdentifier} - Run All Benchmarks"); + Console.Write("> "); try { - string rawInput = Console.ReadLine(); - int choice = int.Parse(rawInput ?? "x"); + string rawInput = Console.ReadLine()?.ToLowerInvariant() ?? "x"; + + if (rawInput.Equals(allBenchmarkIdentifier.ToLowerInvariant())) + { + RunAllBenchmarks(); + + continue; + } + + int choice = int.Parse(rawInput); if (choice < 0 || choice >= Benchmarks.Count) { @@ -92,20 +100,13 @@ namespace NetSharp.Benchmarks private static void RunAllBenchmarks() { - Console.WriteLine("Run all benchmarks? (y/n)"); - Console.Write("> "); - string input = Console.ReadLine()?.ToLowerInvariant() ?? "n"; - - if (input == "y") + foreach (INetSharpBenchmark benchmark in Benchmarks) { - foreach (INetSharpBenchmark benchmark in Benchmarks) - { - Console.WriteLine($"Starting \'{benchmark.Name}\'..."); - benchmark.RunAsync().GetAwaiter().GetResult(); - Console.WriteLine($"Finished \'{benchmark.Name}\'!"); + Console.WriteLine($"Starting \'{benchmark.Name}\'..."); + benchmark.RunAsync().GetAwaiter().GetResult(); + Console.WriteLine($"Finished \'{benchmark.Name}\'!"); - Console.WriteLine(); - } + Console.WriteLine(); } } diff --git a/NetSharp/NetSharp.Examples/Program.cs b/NetSharp/NetSharp.Examples/Program.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Net; using System.Reflection; using System.Resources; @@ -19,17 +20,15 @@ namespace NetSharp.Examples foreach (Type type in Assembly.GetCallingAssembly().GetTypes()) { - if (!type.IsClass && !type.IsValueType) + if (type.IsAbstract) { continue; } Type[] interfaces = type.GetInterfaces(); - object instance = Activator.CreateInstance(type); - - if (type.GetInterface(nameof(INetSharpExample)) == typeof(INetSharpExample)) + if (interfaces.Contains(typeof(INetSharpExample))) { - Examples.Add((INetSharpExample) instance); + Examples.Add((INetSharpExample) Activator.CreateInstance(type)); } } } @@ -58,8 +57,8 @@ namespace NetSharp.Examples try { - string rawInput = Console.ReadLine(); - int choice = int.Parse(rawInput ?? "x"); + string rawInput = Console.ReadLine()?.ToLowerInvariant() ?? "x"; + int choice = int.Parse(rawInput); if (choice < 0 || choice >= Examples.Count) { diff --git a/NetSharp/NetSharp/NetSharp.csproj b/NetSharp/NetSharp/NetSharp.csproj @@ -62,4 +62,8 @@ <LastGenOutput>Resources.Designer.cs</LastGenOutput> </EmbeddedResource> </ItemGroup> + + <ItemGroup> + <Folder Include="Packets\" /> + </ItemGroup> </Project> \ No newline at end of file diff --git a/NetSharp/NetSharp/NetSharp.xml b/NetSharp/NetSharp/NetSharp.xml @@ -98,79 +98,6 @@ The number of bytes of data sent to the remote endpoint. </returns> </member> - <member name="T:NetSharp.Packets.RawStreamPacketHeader"> - <summary> - Holds metadata about a raw stream packet. - </summary> - </member> - <member name="F:NetSharp.Packets.RawStreamPacketHeader.TotalSize"> - <summary> - The total size of the header in bytes. - </summary> - </member> - <member name="F:NetSharp.Packets.RawStreamPacketHeader.DataSize"> - <summary> - The size of the user supplied data segment in bytes. - </summary> - </member> - <member name="M:NetSharp.Packets.RawStreamPacketHeader.#ctor(System.Int32)"> - <summary> - Constructs a new instance of the <see cref="T:NetSharp.Packets.RawStreamPacketHeader" /> struct. - </summary> - <param name="dataSize"> - The size of the user supplied data segment. - </param> - </member> - <member name="M:NetSharp.Packets.RawStreamPacketHeader.Deserialise(System.Memory{System.Byte}@)"> - <summary> - Deserialises a <see cref="T:NetSharp.Packets.RawStreamPacketHeader" /> instance from the given <paramref name="buffer" />. - </summary> - <param name="buffer"> - A buffer containing a serialised <see cref="T:NetSharp.Packets.RawStreamPacketHeader" /> instance. Must be at least of size <see cref="F:NetSharp.Packets.RawStreamPacketHeader.TotalSize" />. - </param> - <returns> - The deserialised instance. - </returns> - </member> - <member name="M:NetSharp.Packets.RawStreamPacketHeader.Serialise(System.Memory{System.Byte}@)"> - <summary> - Serialises the current <see cref="T:NetSharp.Packets.RawStreamPacketHeader" /> instance into the given <paramref name="buffer" />. - </summary> - <param name="buffer"> - The buffer into which to serialise the current instance. Must be at least of size <see cref="F:NetSharp.Packets.RawStreamPacketHeader.TotalSize" />. - </param> - </member> - <member name="T:NetSharp.Packets.RawStreamPacket"> - <summary> - Provides helper methods to manipulate the binary packet format used by stream network handlers. - </summary> - </member> - <member name="M:NetSharp.Packets.RawStreamPacket.Serialise(System.Memory{System.Byte}@,NetSharp.Packets.RawStreamPacketHeader@,System.ReadOnlyMemory{System.Byte}@)"> - <summary> - Serialises the given <paramref name="packetHeader" /> and <paramref name="packetData" /> into the given <paramref name="buffer" />. - </summary> - <param name="buffer"> - The buffer into which the packet should be serialised. Must be at least of size <see cref="F:NetSharp.Packets.RawStreamPacketHeader.TotalSize" /> + the size - of the user data given by <paramref name="packetHeader" />. - </param> - <param name="packetHeader"> - The header containing metatdata abut the raw stream packet. - </param> - <param name="packetData"> - The user data held in the raw stream packet. - </param> - </member> - <member name="M:NetSharp.Packets.RawStreamPacket.TotalPacketSize(NetSharp.Packets.RawStreamPacketHeader@)"> - <summary> - Calculates the total size of a raw stream packet, using the packet data size in the given <paramref name="packetHeader" />. - </summary> - <param name="packetHeader"> - The header for which to calculate the total packet size. - </param> - <returns> - The total size of a raw stream packet with the given <paramref name="packetHeader" />. - </returns> - </member> <member name="T:NetSharp.Properties.Resources"> <summary> A strongly-typed resource class, for looking up localized strings, etc. @@ -484,6 +411,79 @@ <member name="M:NetSharp.Raw.Stream.RawStreamNetworkWriter.WriteAsync(System.Net.EndPoint,System.ReadOnlyMemory{System.Byte},System.Net.Sockets.SocketFlags)"> <inheritdoc /> </member> + <member name="T:NetSharp.Raw.Stream.RawStreamPacketHeader"> + <summary> + Holds metadata about a raw stream packet. + </summary> + </member> + <member name="F:NetSharp.Raw.Stream.RawStreamPacketHeader.TotalSize"> + <summary> + The total size of the header in bytes. + </summary> + </member> + <member name="F:NetSharp.Raw.Stream.RawStreamPacketHeader.DataSize"> + <summary> + The size of the user supplied data segment in bytes. + </summary> + </member> + <member name="M:NetSharp.Raw.Stream.RawStreamPacketHeader.#ctor(System.Int32)"> + <summary> + Constructs a new instance of the <see cref="T:NetSharp.Raw.Stream.RawStreamPacketHeader" /> struct. + </summary> + <param name="dataSize"> + The size of the user supplied data segment. + </param> + </member> + <member name="M:NetSharp.Raw.Stream.RawStreamPacketHeader.Deserialise(System.Memory{System.Byte}@)"> + <summary> + Deserialises a <see cref="T:NetSharp.Raw.Stream.RawStreamPacketHeader" /> instance from the given <paramref name="buffer" />. + </summary> + <param name="buffer"> + A buffer containing a serialised <see cref="T:NetSharp.Raw.Stream.RawStreamPacketHeader" /> instance. Must be at least of size <see cref="F:NetSharp.Raw.Stream.RawStreamPacketHeader.TotalSize" />. + </param> + <returns> + The deserialised instance. + </returns> + </member> + <member name="M:NetSharp.Raw.Stream.RawStreamPacketHeader.Serialise(System.Memory{System.Byte}@)"> + <summary> + Serialises the current <see cref="T:NetSharp.Raw.Stream.RawStreamPacketHeader" /> instance into the given <paramref name="buffer" />. + </summary> + <param name="buffer"> + The buffer into which to serialise the current instance. Must be at least of size <see cref="F:NetSharp.Raw.Stream.RawStreamPacketHeader.TotalSize" />. + </param> + </member> + <member name="T:NetSharp.Raw.Stream.RawStreamPacket"> + <summary> + Provides helper methods to manipulate the binary packet format used by stream network handlers. + </summary> + </member> + <member name="M:NetSharp.Raw.Stream.RawStreamPacket.Serialise(System.Memory{System.Byte}@,NetSharp.Raw.Stream.RawStreamPacketHeader@,System.ReadOnlyMemory{System.Byte}@)"> + <summary> + Serialises the given <paramref name="packetHeader" /> and <paramref name="packetData" /> into the given <paramref name="buffer" />. + </summary> + <param name="buffer"> + The buffer into which the packet should be serialised. Must be at least of size <see cref="F:NetSharp.Raw.Stream.RawStreamPacketHeader.TotalSize" /> + the size + of the user data given by <paramref name="packetHeader" />. + </param> + <param name="packetHeader"> + The header containing metatdata abut the raw stream packet. + </param> + <param name="packetData"> + The user data held in the raw stream packet. + </param> + </member> + <member name="M:NetSharp.Raw.Stream.RawStreamPacket.TotalPacketSize(NetSharp.Raw.Stream.RawStreamPacketHeader@)"> + <summary> + Calculates the total size of a raw stream packet, using the packet data size in the given <paramref name="packetHeader" />. + </summary> + <param name="packetHeader"> + The header for which to calculate the total packet size. + </param> + <returns> + The total size of a raw stream packet with the given <paramref name="packetHeader" />. + </returns> + </member> <member name="T:NetSharp.Utils.Conversion.EndianAwareBitConverter"> <summary> Wraps the <see cref="T:System.BitConverter" /> class to provide conversion that is endian-aware. diff --git a/NetSharp/NetSharp/Packets/RawStreamPacket.cs b/NetSharp/NetSharp/Packets/RawStreamPacket.cs @@ -1,107 +0,0 @@ -using System; -using System.Runtime.CompilerServices; - -using NetSharp.Utils.Conversion; - -namespace NetSharp.Packets -{ - /// <summary> - /// Holds metadata about a raw stream packet. - /// </summary> - internal readonly struct RawStreamPacketHeader - { - /// <summary> - /// The total size of the header in bytes. - /// </summary> - internal const int TotalSize = sizeof(int); - - /// <summary> - /// The size of the user supplied data segment in bytes. - /// </summary> - internal readonly int DataSize; - - /// <summary> - /// Constructs a new instance of the <see cref="RawStreamPacketHeader" /> struct. - /// </summary> - /// <param name="dataSize"> - /// The size of the user supplied data segment. - /// </param> - internal RawStreamPacketHeader(int dataSize) - { - DataSize = dataSize; - } - - /// <summary> - /// Deserialises a <see cref="RawStreamPacketHeader" /> instance from the given <paramref name="buffer" />. - /// </summary> - /// <param name="buffer"> - /// A buffer containing a serialised <see cref="RawStreamPacketHeader" /> instance. Must be at least of size <see cref="TotalSize" />. - /// </param> - /// <returns> - /// The deserialised instance. - /// </returns> - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static RawStreamPacketHeader Deserialise(in Memory<byte> buffer) - { - Span<byte> serialisedDataSize = buffer.Slice(0, sizeof(int)).Span; - int dataSize = EndianAwareBitConverter.ToInt32(serialisedDataSize); - - return new RawStreamPacketHeader(dataSize); - } - - /// <summary> - /// Serialises the current <see cref="RawStreamPacketHeader" /> instance into the given <paramref name="buffer" />. - /// </summary> - /// <param name="buffer"> - /// The buffer into which to serialise the current instance. Must be at least of size <see cref="TotalSize" />. - /// </param> - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void Serialise(in Memory<byte> buffer) - { - Span<byte> serialisedDataSize = EndianAwareBitConverter.GetBytes(DataSize); - serialisedDataSize.CopyTo(buffer.Slice(0, sizeof(int)).Span); - } - } - - /// <summary> - /// Provides helper methods to manipulate the binary packet format used by stream network handlers. - /// </summary> - internal static class RawStreamPacket - { - /// <summary> - /// Serialises the given <paramref name="packetHeader" /> and <paramref name="packetData" /> into the given <paramref name="buffer" />. - /// </summary> - /// <param name="buffer"> - /// The buffer into which the packet should be serialised. Must be at least of size <see cref="RawStreamPacketHeader.TotalSize" /> + the size - /// of the user data given by <paramref name="packetHeader" />. - /// </param> - /// <param name="packetHeader"> - /// The header containing metatdata abut the raw stream packet. - /// </param> - /// <param name="packetData"> - /// The user data held in the raw stream packet. - /// </param> - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static void Serialise(in Memory<byte> buffer, in RawStreamPacketHeader packetHeader, in ReadOnlyMemory<byte> packetData) - { - packetHeader.Serialise(buffer.Slice(0, RawStreamPacketHeader.TotalSize)); - - packetData.CopyTo(buffer.Slice(RawStreamPacketHeader.TotalSize, packetData.Length)); - } - - /// <summary> - /// Calculates the total size of a raw stream packet, using the packet data size in the given <paramref name="packetHeader" />. - /// </summary> - /// <param name="packetHeader"> - /// The header for which to calculate the total packet size. - /// </param> - /// <returns> - /// The total size of a raw stream packet with the given <paramref name="packetHeader" />. - /// </returns> - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static int TotalPacketSize(in RawStreamPacketHeader packetHeader) - { - return RawStreamPacketHeader.TotalSize + packetHeader.DataSize; - } - } -} -\ No newline at end of file diff --git a/NetSharp/NetSharp/Raw/Datagram/RawDatagramNetworkWriter.cs b/NetSharp/NetSharp/Raw/Datagram/RawDatagramNetworkWriter.cs @@ -181,8 +181,7 @@ namespace NetSharp.Raw.Datagram } /// <inheritdoc /> - public override int Write(EndPoint remoteEndPoint, ReadOnlyMemory<byte> writeBuffer, - SocketFlags flags = SocketFlags.None) + public override int Write(EndPoint remoteEndPoint, ReadOnlyMemory<byte> writeBuffer, SocketFlags flags = SocketFlags.None) { int totalBytes = writeBuffer.Length; if (totalBytes > datagramSize) diff --git a/NetSharp/NetSharp/Raw/Stream/RawStreamNetworkReader.cs b/NetSharp/NetSharp/Raw/Stream/RawStreamNetworkReader.cs @@ -2,8 +2,6 @@ using System.Net; using System.Net.Sockets; -using NetSharp.Packets; - namespace NetSharp.Raw.Stream { /// <summary> diff --git a/NetSharp/NetSharp/Raw/Stream/RawStreamNetworkWriter.cs b/NetSharp/NetSharp/Raw/Stream/RawStreamNetworkWriter.cs @@ -3,8 +3,6 @@ using System.Net; using System.Net.Sockets; using System.Threading.Tasks; -using NetSharp.Packets; - namespace NetSharp.Raw.Stream { /// <summary> diff --git a/NetSharp/NetSharp/Raw/Stream/RawStreamPacket.cs b/NetSharp/NetSharp/Raw/Stream/RawStreamPacket.cs @@ -0,0 +1,107 @@ +using System; +using System.Runtime.CompilerServices; + +using NetSharp.Utils.Conversion; + +namespace NetSharp.Raw.Stream +{ + /// <summary> + /// Holds metadata about a raw stream packet. + /// </summary> + internal readonly struct RawStreamPacketHeader + { + /// <summary> + /// The total size of the header in bytes. + /// </summary> + internal const int TotalSize = sizeof(int); + + /// <summary> + /// The size of the user supplied data segment in bytes. + /// </summary> + internal readonly int DataSize; + + /// <summary> + /// Constructs a new instance of the <see cref="RawStreamPacketHeader" /> struct. + /// </summary> + /// <param name="dataSize"> + /// The size of the user supplied data segment. + /// </param> + internal RawStreamPacketHeader(int dataSize) + { + DataSize = dataSize; + } + + /// <summary> + /// Deserialises a <see cref="RawStreamPacketHeader" /> instance from the given <paramref name="buffer" />. + /// </summary> + /// <param name="buffer"> + /// A buffer containing a serialised <see cref="RawStreamPacketHeader" /> instance. Must be at least of size <see cref="TotalSize" />. + /// </param> + /// <returns> + /// The deserialised instance. + /// </returns> + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static RawStreamPacketHeader Deserialise(in Memory<byte> buffer) + { + Span<byte> serialisedDataSize = buffer.Slice(0, sizeof(int)).Span; + int dataSize = EndianAwareBitConverter.ToInt32(serialisedDataSize); + + return new RawStreamPacketHeader(dataSize); + } + + /// <summary> + /// Serialises the current <see cref="RawStreamPacketHeader" /> instance into the given <paramref name="buffer" />. + /// </summary> + /// <param name="buffer"> + /// The buffer into which to serialise the current instance. Must be at least of size <see cref="TotalSize" />. + /// </param> + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal void Serialise(in Memory<byte> buffer) + { + Span<byte> serialisedDataSize = EndianAwareBitConverter.GetBytes(DataSize); + serialisedDataSize.CopyTo(buffer.Slice(0, sizeof(int)).Span); + } + } + + /// <summary> + /// Provides helper methods to manipulate the binary packet format used by stream network handlers. + /// </summary> + internal static class RawStreamPacket + { + /// <summary> + /// Serialises the given <paramref name="packetHeader" /> and <paramref name="packetData" /> into the given <paramref name="buffer" />. + /// </summary> + /// <param name="buffer"> + /// The buffer into which the packet should be serialised. Must be at least of size <see cref="RawStreamPacketHeader.TotalSize" /> + the size + /// of the user data given by <paramref name="packetHeader" />. + /// </param> + /// <param name="packetHeader"> + /// The header containing metatdata abut the raw stream packet. + /// </param> + /// <param name="packetData"> + /// The user data held in the raw stream packet. + /// </param> + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static void Serialise(in Memory<byte> buffer, in RawStreamPacketHeader packetHeader, in ReadOnlyMemory<byte> packetData) + { + packetHeader.Serialise(buffer.Slice(0, RawStreamPacketHeader.TotalSize)); + + packetData.CopyTo(buffer.Slice(RawStreamPacketHeader.TotalSize, packetData.Length)); + } + + /// <summary> + /// Calculates the total size of a raw stream packet, using the packet data size in the given <paramref name="packetHeader" />. + /// </summary> + /// <param name="packetHeader"> + /// The header for which to calculate the total packet size. + /// </param> + /// <returns> + /// The total size of a raw stream packet with the given <paramref name="packetHeader" />. + /// </returns> + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static int TotalPacketSize(in RawStreamPacketHeader packetHeader) + { + return RawStreamPacketHeader.TotalSize + packetHeader.DataSize; + } + } +} +\ No newline at end of file diff --git a/docs/datagram-network-reader-benchmark.png b/docs/datagram-network-reader-benchmark.png Binary files differ. diff --git a/docs/datagram-network-writer-benchmark.png b/docs/datagram-network-writer-benchmark.png Binary files differ. diff --git a/docs/example-selector.png b/docs/example-selector.png Binary files differ. diff --git a/docs/stream-network-reader-benchmark.png b/docs/stream-network-reader-benchmark.png Binary files differ. diff --git a/docs/stream-network-writer-benchmark.png b/docs/stream-network-writer-benchmark.png Binary files differ.