NetSharp

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

commit 8344ed3d9eec5a4023e3032266f4219c0a1ae64a
parent e1d914f7143c7350688f32a935dfab824aaa2a8c
Author: Mikolaj Lenczewski <mikolaj.lenczewski308@gmail.com>
Date:   Mon,  4 May 2020 22:30:58 +0100

Implemented Connect and Disconnect methods for NetworkWriters (Disconnect is only for StreamNetworkWriter). Added examples of usage.

Diffstat:
MNetSharp/NetSharp/NetSharp.xml | 12++++++++++++
MNetSharp/NetSharp/Raw/Datagram/DatagramNetworkWriter.cs | 70++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------------
MNetSharp/NetSharp/Raw/NetworkWriterBase.cs | 14++++++++++++++
MNetSharp/NetSharp/Raw/Stream/StreamNetworkWriter.cs | 104++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------
MNetSharp/NetSharpExamples/Benchmarks/Datagram Network Connection Benchmarks/DatagramNetworkWriterAsyncBenchmark.cs | 2+-
MNetSharp/NetSharpExamples/Benchmarks/Datagram Network Connection Benchmarks/DatagramNetworkWriterSyncBenchmark.cs | 2+-
MNetSharp/NetSharpExamples/Benchmarks/Stream Network Connection Benchmarks/StreamNetworkWriterAsyncBenchmark.cs | 2+-
MNetSharp/NetSharpExamples/Benchmarks/Stream Network Connection Benchmarks/StreamNetworkWriterSyncBenchmark.cs | 2+-
ANetSharp/NetSharpExamples/Examples/Datagram Network Connection Examples/DatagramNetworkReaderExample.cs | 55+++++++++++++++++++++++++++++++++++++++++++++++++++++++
ANetSharp/NetSharpExamples/Examples/Datagram Network Connection Examples/DatagramNetworkWriterAsyncExample.cs | 57+++++++++++++++++++++++++++++++++++++++++++++++++++++++++
ANetSharp/NetSharpExamples/Examples/Datagram Network Connection Examples/DatagramNetworkWriterSyncExample.cs | 59+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
ANetSharp/NetSharpExamples/Examples/Stream Network Connection Examples/StreamNetworkReaderExample.cs | 56++++++++++++++++++++++++++++++++++++++++++++++++++++++++
ANetSharp/NetSharpExamples/Examples/Stream Network Connection Examples/StreamNetworkWriterAsyncExample.cs | 60++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
ANetSharp/NetSharpExamples/Examples/Stream Network Connection Examples/StreamNetworkWriterSyncExample.cs | 62++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
MNetSharp/NetSharpExamples/NetSharpExamples.csproj | 5-----
MNetSharp/NetSharpExamples/NetSharpExamples.xml | 36++++++++++++++++++++++++++++++++++++
MREADME.md | 12++++++------
Rdocs/datagram-network-listener-benchmark.png -> docs/datagram-network-reader-benchmark.png | 0
Rdocs/stream-network-listener-benchmark.png -> docs/stream-network-reader-benchmark.png | 0
19 files changed, 570 insertions(+), 40 deletions(-)

diff --git a/NetSharp/NetSharp/NetSharp.xml b/NetSharp/NetSharp/NetSharp.xml @@ -189,6 +189,12 @@ <member name="M:NetSharp.Raw.Datagram.DatagramNetworkWriter.ResetStateObject(System.Net.Sockets.SocketAsyncEventArgs@)"> <inheritdoc /> </member> + <member name="M:NetSharp.Raw.Datagram.DatagramNetworkWriter.Connect(System.Net.EndPoint)"> + <inheritdoc /> + </member> + <member name="M:NetSharp.Raw.Datagram.DatagramNetworkWriter.ConnectAsync(System.Net.EndPoint)"> + <inheritdoc /> + </member> <member name="M:NetSharp.Raw.Datagram.DatagramNetworkWriter.Read(System.Net.EndPoint@,System.Memory{System.Byte},System.Net.Sockets.SocketFlags)"> <inheritdoc /> </member> @@ -251,6 +257,12 @@ <member name="M:NetSharp.Raw.Stream.StreamNetworkWriter.ResetStateObject(System.Net.Sockets.SocketAsyncEventArgs@)"> <inheritdoc /> </member> + <member name="M:NetSharp.Raw.Stream.StreamNetworkWriter.Connect(System.Net.EndPoint)"> + <inheritdoc /> + </member> + <member name="M:NetSharp.Raw.Stream.StreamNetworkWriter.ConnectAsync(System.Net.EndPoint)"> + <inheritdoc /> + </member> <member name="M:NetSharp.Raw.Stream.StreamNetworkWriter.Read(System.Net.EndPoint@,System.Memory{System.Byte},System.Net.Sockets.SocketFlags)"> <inheritdoc /> </member> diff --git a/NetSharp/NetSharp/Raw/Datagram/DatagramNetworkWriter.cs b/NetSharp/NetSharp/Raw/Datagram/DatagramNetworkWriter.cs @@ -13,11 +13,34 @@ namespace NetSharp.Raw.Datagram { } + private void CompleteConnect(SocketAsyncEventArgs args) + { + AsyncOperationToken token = (AsyncOperationToken)args.UserToken; + + switch (args.SocketError) + { + case SocketError.Success: + token.CompletionSource.SetResult(true); + break; + + case SocketError.OperationAborted: + token.CompletionSource.SetCanceled(); + break; + + default: + int errorCode = (int)args.SocketError; + token.CompletionSource.SetException(new SocketException(errorCode)); + break; + } + + StateObjectPool.Return(args); + } + private void CompleteReceiveFrom(SocketAsyncEventArgs args) { AsyncDatagramReadToken token = (AsyncDatagramReadToken)args.UserToken; - byte[] receiveBuffer = token.TransmissionBuffer; + byte[] receiveBuffer = args.Buffer; switch (args.SocketError) { @@ -44,7 +67,7 @@ namespace NetSharp.Raw.Datagram { AsyncDatagramWriteToken token = (AsyncDatagramWriteToken)args.UserToken; - byte[] sendBuffer = token.TransmissionBuffer; + byte[] sendBuffer = args.Buffer; switch (args.SocketError) { @@ -71,6 +94,7 @@ namespace NetSharp.Raw.Datagram switch (args.LastOperation) { case SocketAsyncOperation.Connect: + CompleteConnect(args); break; case SocketAsyncOperation.SendTo: @@ -111,6 +135,30 @@ namespace NetSharp.Raw.Datagram } /// <inheritdoc /> + public override void Connect(EndPoint remoteEndPoint) + { + Connection.Connect(remoteEndPoint); + } + + /// <inheritdoc /> + public override ValueTask ConnectAsync(EndPoint remoteEndPoint) + { + TaskCompletionSource<bool> tcs = new TaskCompletionSource<bool>(); + SocketAsyncEventArgs args = StateObjectPool.Rent(); + + args.RemoteEndPoint = remoteEndPoint; + + AsyncOperationToken token = new AsyncOperationToken(tcs); + args.UserToken = token; + + if (Connection.ConnectAsync(args)) return new ValueTask(tcs.Task); + + StateObjectPool.Return(args); + + return new ValueTask(); + } + + /// <inheritdoc /> public override int Read(ref EndPoint remoteEndPoint, Memory<byte> readBuffer, SocketFlags flags = SocketFlags.None) { int totalBytes = readBuffer.Length; @@ -149,12 +197,12 @@ namespace NetSharp.Raw.Datagram byte[] transmissionBuffer = BufferPool.Rent(BufferSize); - args.SetBuffer(transmissionBuffer); + args.SetBuffer(transmissionBuffer, 0, BufferSize); args.RemoteEndPoint = remoteEndPoint; args.SocketFlags = flags; - AsyncDatagramReadToken token = new AsyncDatagramReadToken(tcs, ref transmissionBuffer, in readBuffer); + AsyncDatagramReadToken token = new AsyncDatagramReadToken(tcs, in readBuffer); args.UserToken = token; if (Connection.ReceiveFromAsync(args)) return new ValueTask<int>(tcs.Task); @@ -210,12 +258,12 @@ namespace NetSharp.Raw.Datagram byte[] transmissionBuffer = BufferPool.Rent(BufferSize); writeBuffer.CopyTo(transmissionBuffer); - args.SetBuffer(transmissionBuffer); + args.SetBuffer(transmissionBuffer, 0, BufferSize); args.RemoteEndPoint = remoteEndPoint; args.SocketFlags = flags; - AsyncDatagramWriteToken token = new AsyncDatagramWriteToken(tcs, ref transmissionBuffer); + AsyncDatagramWriteToken token = new AsyncDatagramWriteToken(tcs); args.UserToken = token; if (Connection.SendToAsync(args)) return new ValueTask<int>(tcs.Task); @@ -231,15 +279,12 @@ namespace NetSharp.Raw.Datagram private readonly struct AsyncDatagramReadToken { public readonly TaskCompletionSource<int> CompletionSource; - public readonly byte[] TransmissionBuffer; public readonly Memory<byte> UserBuffer; - public AsyncDatagramReadToken(TaskCompletionSource<int> completionSource, ref byte[] transmissionBuffer, in Memory<byte> userBuffer) + public AsyncDatagramReadToken(TaskCompletionSource<int> completionSource, in Memory<byte> userBuffer) { CompletionSource = completionSource; - TransmissionBuffer = transmissionBuffer; - UserBuffer = userBuffer; } } @@ -247,13 +292,10 @@ namespace NetSharp.Raw.Datagram private readonly struct AsyncDatagramWriteToken { public readonly TaskCompletionSource<int> CompletionSource; - public readonly byte[] TransmissionBuffer; - public AsyncDatagramWriteToken(TaskCompletionSource<int> completionSource, ref byte[] transmissionBuffer) + public AsyncDatagramWriteToken(TaskCompletionSource<int> completionSource) { CompletionSource = completionSource; - - TransmissionBuffer = transmissionBuffer; } } } diff --git a/NetSharp/NetSharp/Raw/NetworkWriterBase.cs b/NetSharp/NetSharp/Raw/NetworkWriterBase.cs @@ -13,6 +13,10 @@ namespace NetSharp.Raw { } + public abstract void Connect(EndPoint remoteEndPoint); + + public abstract ValueTask ConnectAsync(EndPoint remoteEndPoint); + public abstract int Read(ref EndPoint remoteEndPoint, Memory<byte> readBuffer, SocketFlags flags = SocketFlags.None); @@ -24,5 +28,15 @@ namespace NetSharp.Raw public abstract ValueTask<int> WriteAsync(EndPoint remoteEndPoint, ReadOnlyMemory<byte> writeBuffer, SocketFlags flags = SocketFlags.None); + + protected readonly struct AsyncOperationToken + { + public readonly TaskCompletionSource<bool> CompletionSource; + + public AsyncOperationToken(TaskCompletionSource<bool> completionSource) + { + CompletionSource = completionSource; + } + } } } \ No newline at end of file diff --git a/NetSharp/NetSharp/Raw/Stream/StreamNetworkWriter.cs b/NetSharp/NetSharp/Raw/Stream/StreamNetworkWriter.cs @@ -16,12 +16,48 @@ namespace NetSharp.Raw.Stream private void CompleteConnect(SocketAsyncEventArgs args) { - throw new NotImplementedException(); + AsyncOperationToken token = (AsyncOperationToken)args.UserToken; + + switch (args.SocketError) + { + case SocketError.Success: + token.CompletionSource.SetResult(true); + break; + + case SocketError.OperationAborted: + token.CompletionSource.SetCanceled(); + break; + + default: + int errorCode = (int)args.SocketError; + token.CompletionSource.SetException(new SocketException(errorCode)); + break; + } + + StateObjectPool.Return(args); } private void CompleteDisconnect(SocketAsyncEventArgs args) { - throw new NotImplementedException(); + AsyncOperationToken token = (AsyncOperationToken)args.UserToken; + + switch (args.SocketError) + { + case SocketError.Success: + token.CompletionSource.SetResult(true); + break; + + case SocketError.OperationAborted: + token.CompletionSource.SetCanceled(); + break; + + default: + int errorCode = (int)args.SocketError; + token.CompletionSource.SetException(new SocketException(errorCode)); + break; + } + + StateObjectPool.Return(args); } private void CompleteReceive(SocketAsyncEventArgs args) @@ -36,9 +72,10 @@ namespace NetSharp.Raw.Stream case SocketError.Success: int receivedBytes = args.BytesTransferred, totalReceivedBytes = token.TotalReadBytes; - if (receivedBytes == 0) // connection is dead + if (totalReceivedBytes + receivedBytes == expectedBytes) // transmission complete { - token.CompletionSource.SetException(new SocketException((int)SocketError.HostDown)); + receiveBufferHandle.CopyTo(token.UserBuffer); + token.CompletionSource.SetResult(args.BytesTransferred); } else if (0 < totalReceivedBytes + receivedBytes && totalReceivedBytes + receivedBytes < expectedBytes) // transmission not complete { @@ -51,10 +88,9 @@ namespace NetSharp.Raw.Stream ContinueReceive(args); return; } - else if (totalReceivedBytes + receivedBytes == expectedBytes) // transmission complete + else if (receivedBytes == 0) // connection is dead { - receiveBufferHandle.CopyTo(token.UserBuffer); - token.CompletionSource.SetResult(args.BytesTransferred); + token.CompletionSource.SetException(new SocketException((int)SocketError.HostDown)); } break; @@ -84,9 +120,9 @@ namespace NetSharp.Raw.Stream case SocketError.Success: int sentBytes = args.BytesTransferred, totalSentBytes = token.TotalWrittenBytes; - if (sentBytes == 0) // connection is dead + if (totalSentBytes + sentBytes == expectedBytes) // transmission complete { - token.CompletionSource.SetException(new SocketException((int)SocketError.HostDown)); + token.CompletionSource.SetResult(args.BytesTransferred); } else if (0 < totalSentBytes + sentBytes && totalSentBytes + sentBytes < expectedBytes) // transmission not complete { @@ -99,9 +135,9 @@ namespace NetSharp.Raw.Stream ContinueSend(args); return; } - else if (totalSentBytes + sentBytes == expectedBytes) // transmission complete + else if (sentBytes == 0) // connection is dead { - token.CompletionSource.SetResult(args.BytesTransferred); + token.CompletionSource.SetException(new SocketException((int)SocketError.HostDown)); } break; @@ -185,6 +221,52 @@ namespace NetSharp.Raw.Stream } /// <inheritdoc /> + public override void Connect(EndPoint remoteEndPoint) + { + Connection.Connect(remoteEndPoint); + } + + /// <inheritdoc /> + public override ValueTask ConnectAsync(EndPoint remoteEndPoint) + { + TaskCompletionSource<bool> tcs = new TaskCompletionSource<bool>(); + SocketAsyncEventArgs args = StateObjectPool.Rent(); + + args.RemoteEndPoint = remoteEndPoint; + + AsyncOperationToken token = new AsyncOperationToken(tcs); + args.UserToken = token; + + if (Connection.ConnectAsync(args)) return new ValueTask(tcs.Task); + + StateObjectPool.Return(args); + + return new ValueTask(); + } + + public void Disconnect(bool reuseSocket) + { + Connection.Disconnect(reuseSocket); + } + + public ValueTask DisconnectAsync(bool reuseSocket) + { + TaskCompletionSource<bool> tcs = new TaskCompletionSource<bool>(); + SocketAsyncEventArgs args = StateObjectPool.Rent(); + + args.DisconnectReuseSocket = reuseSocket; + + AsyncOperationToken token = new AsyncOperationToken(tcs); + args.UserToken = token; + + if (Connection.DisconnectAsync(args)) return new ValueTask(tcs.Task); + + StateObjectPool.Return(args); + + return new ValueTask(); + } + + /// <inheritdoc /> public override int Read(ref EndPoint remoteEndPoint, Memory<byte> readBuffer, SocketFlags flags = SocketFlags.None) { int totalBytes = readBuffer.Length; diff --git a/NetSharp/NetSharpExamples/Benchmarks/Datagram Network Connection Benchmarks/DatagramNetworkWriterAsyncBenchmark.cs b/NetSharp/NetSharpExamples/Benchmarks/Datagram Network Connection Benchmarks/DatagramNetworkWriterAsyncBenchmark.cs @@ -16,7 +16,7 @@ namespace NetSharpExamples.Benchmarks.Datagram_Network_Connection_Benchmarks public static readonly EndPoint ClientEndPoint = new IPEndPoint(IPAddress.Loopback, 0); public static readonly Encoding ServerEncoding = Encoding.UTF8; - public static readonly EndPoint ServerEndPoint = new IPEndPoint(IPAddress.Loopback, 12372); + public static readonly EndPoint ServerEndPoint = new IPEndPoint(IPAddress.Loopback, 12371); public static readonly ManualResetEventSlim ServerReadyEvent = new ManualResetEventSlim(); diff --git a/NetSharp/NetSharpExamples/Benchmarks/Datagram Network Connection Benchmarks/DatagramNetworkWriterSyncBenchmark.cs b/NetSharp/NetSharpExamples/Benchmarks/Datagram Network Connection Benchmarks/DatagramNetworkWriterSyncBenchmark.cs @@ -16,7 +16,7 @@ namespace NetSharpExamples.Benchmarks.Datagram_Network_Connection_Benchmarks public static readonly EndPoint ClientEndPoint = new IPEndPoint(IPAddress.Loopback, 0); public static readonly Encoding ServerEncoding = Encoding.UTF8; - public static readonly EndPoint ServerEndPoint = new IPEndPoint(IPAddress.Loopback, 12371); + public static readonly EndPoint ServerEndPoint = new IPEndPoint(IPAddress.Loopback, 12372); public static readonly ManualResetEventSlim ServerReadyEvent = new ManualResetEventSlim(); diff --git a/NetSharp/NetSharpExamples/Benchmarks/Stream Network Connection Benchmarks/StreamNetworkWriterAsyncBenchmark.cs b/NetSharp/NetSharpExamples/Benchmarks/Stream Network Connection Benchmarks/StreamNetworkWriterAsyncBenchmark.cs @@ -16,7 +16,7 @@ namespace NetSharpExamples.Benchmarks.Stream_Network_Connection_Benchmarks public static readonly EndPoint ClientEndPoint = new IPEndPoint(IPAddress.Loopback, 0); public static readonly Encoding ServerEncoding = Encoding.UTF8; - public static readonly EndPoint ServerEndPoint = new IPEndPoint(IPAddress.Loopback, 12375); + public static readonly EndPoint ServerEndPoint = new IPEndPoint(IPAddress.Loopback, 12374); public static readonly ManualResetEventSlim ServerReadyEvent = new ManualResetEventSlim(); diff --git a/NetSharp/NetSharpExamples/Benchmarks/Stream Network Connection Benchmarks/StreamNetworkWriterSyncBenchmark.cs b/NetSharp/NetSharpExamples/Benchmarks/Stream Network Connection Benchmarks/StreamNetworkWriterSyncBenchmark.cs @@ -16,7 +16,7 @@ namespace NetSharpExamples.Benchmarks.Stream_Network_Connection_Benchmarks public static readonly EndPoint ClientEndPoint = new IPEndPoint(IPAddress.Loopback, 0); public static readonly Encoding ServerEncoding = Encoding.UTF8; - public static readonly EndPoint ServerEndPoint = new IPEndPoint(IPAddress.Loopback, 12374); + public static readonly EndPoint ServerEndPoint = new IPEndPoint(IPAddress.Loopback, 12375); public static readonly ManualResetEventSlim ServerReadyEvent = new ManualResetEventSlim(); diff --git a/NetSharp/NetSharpExamples/Examples/Datagram Network Connection Examples/DatagramNetworkReaderExample.cs b/NetSharp/NetSharpExamples/Examples/Datagram Network Connection Examples/DatagramNetworkReaderExample.cs @@ -0,0 +1,54 @@ +using NetSharp.Raw.Datagram; + +using System; +using System.Net; +using System.Net.Sockets; +using System.Text; +using System.Threading.Tasks; + +namespace NetSharpExamples.Examples.Datagram_Network_Connection_Examples +{ + public class DatagramNetworkReaderExample : INetSharpExample + { + private const int PacketSize = 8192, ExpectedClientCount = 8; + public static readonly Encoding ServerEncoding = Encoding.UTF8; + public static readonly EndPoint ServerEndPoint = new IPEndPoint(IPAddress.Loopback, 12376); + + /// <inheritdoc /> + public string Name { get; } = "Datagram Network Reader Example"; + + private static bool RequestHandler(in EndPoint remoteEndPoint, ReadOnlyMemory<byte> requestBuffer, int receivedRequestBytes, Memory<byte> responseBuffer) + { + requestBuffer.CopyTo(responseBuffer); + + lock (typeof(Console)) + { + Console.WriteLine($"Received {receivedRequestBytes} bytes from {remoteEndPoint}! Echoing back..."); + } + + return true; + } + + /// <inheritdoc /> + public Task RunAsync() + { + EndPoint defaultEndPoint = new IPEndPoint(IPAddress.Any, 0); + + Socket rawSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); + rawSocket.Bind(ServerEndPoint); + + using DatagramNetworkReader reader = new DatagramNetworkReader(ref rawSocket, RequestHandler, defaultEndPoint, PacketSize, 100); + reader.Start(ExpectedClientCount); + + Console.WriteLine($"Started datagram server at {ServerEndPoint}! Enter any key to stop the server..."); + Console.ReadLine(); + + reader.Stop(); + + rawSocket.Close(); + rawSocket.Dispose(); + + return Task.CompletedTask; + } + } +} +\ No newline at end of file diff --git a/NetSharp/NetSharpExamples/Examples/Datagram Network Connection Examples/DatagramNetworkWriterAsyncExample.cs b/NetSharp/NetSharpExamples/Examples/Datagram Network Connection Examples/DatagramNetworkWriterAsyncExample.cs @@ -0,0 +1,56 @@ +using NetSharp.Raw.Datagram; + +using System; +using System.Net; +using System.Net.Sockets; +using System.Threading.Tasks; + +namespace NetSharpExamples.Examples.Datagram_Network_Connection_Examples +{ + public class DatagramNetworkWriterAsyncExample : INetSharpExample + { + private const int PacketSize = 8192; + + public static readonly EndPoint ClientEndPoint = new IPEndPoint(IPAddress.Loopback, 0); + + public static readonly EndPoint ServerEndPoint = DatagramNetworkReaderExample.ServerEndPoint; + + /// <inheritdoc /> + public string Name { get; } = "Datagram Network Writer Example (Asynchronous)"; + + /// <inheritdoc /> + public async Task RunAsync() + { + EndPoint defaultEndPoint = new IPEndPoint(IPAddress.Any, 0); + + Socket rawSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); + rawSocket.Bind(ClientEndPoint); + + using DatagramNetworkWriter writer = new DatagramNetworkWriter(ref rawSocket, defaultEndPoint, PacketSize); + + byte[] transmissionBuffer = new byte[PacketSize]; + + EndPoint remoteEndPoint = ServerEndPoint; + + while (true) + { + int sent = await writer.WriteAsync(remoteEndPoint, transmissionBuffer); + + lock (typeof(Console)) + { + Console.WriteLine($"Sent {sent} bytes to {remoteEndPoint}!"); + } + + int received = await writer.ReadAsync(remoteEndPoint, transmissionBuffer); + + lock (typeof(Console)) + { + Console.WriteLine($"Received {received} bytes from {remoteEndPoint}!"); + } + } + + rawSocket.Close(); + rawSocket.Dispose(); + } + } +} +\ No newline at end of file diff --git a/NetSharp/NetSharpExamples/Examples/Datagram Network Connection Examples/DatagramNetworkWriterSyncExample.cs b/NetSharp/NetSharpExamples/Examples/Datagram Network Connection Examples/DatagramNetworkWriterSyncExample.cs @@ -0,0 +1,58 @@ +using NetSharp.Raw.Datagram; + +using System; +using System.Net; +using System.Net.Sockets; +using System.Threading.Tasks; + +namespace NetSharpExamples.Examples.Datagram_Network_Connection_Examples +{ + public class DatagramNetworkWriterSyncExample : INetSharpExample + { + private const int PacketSize = 8192; + + public static readonly EndPoint ClientEndPoint = new IPEndPoint(IPAddress.Loopback, 0); + + public static readonly EndPoint ServerEndPoint = DatagramNetworkReaderExample.ServerEndPoint; + + /// <inheritdoc /> + public string Name { get; } = "Datagram Network Writer Example (Synchronous)"; + + /// <inheritdoc /> + public Task RunAsync() + { + EndPoint defaultEndPoint = new IPEndPoint(IPAddress.Any, 0); + + Socket rawSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); + rawSocket.Bind(ClientEndPoint); + + using DatagramNetworkWriter writer = new DatagramNetworkWriter(ref rawSocket, defaultEndPoint, PacketSize); + + byte[] transmissionBuffer = new byte[PacketSize]; + + EndPoint remoteEndPoint = ServerEndPoint; + + while (true) + { + int sent = writer.Write(remoteEndPoint, transmissionBuffer); + + lock (typeof(Console)) + { + Console.WriteLine($"Sent {sent} bytes to {remoteEndPoint}!"); + } + + int received = writer.Read(ref remoteEndPoint, transmissionBuffer); + + lock (typeof(Console)) + { + Console.WriteLine($"Received {received} bytes from {remoteEndPoint}!"); + } + } + + rawSocket.Close(); + rawSocket.Dispose(); + + return Task.CompletedTask; + } + } +} +\ No newline at end of file diff --git a/NetSharp/NetSharpExamples/Examples/Stream Network Connection Examples/StreamNetworkReaderExample.cs b/NetSharp/NetSharpExamples/Examples/Stream Network Connection Examples/StreamNetworkReaderExample.cs @@ -0,0 +1,55 @@ +using NetSharp.Raw.Stream; + +using System; +using System.Net; +using System.Net.Sockets; +using System.Text; +using System.Threading.Tasks; + +namespace NetSharpExamples.Examples.Stream_Network_Connection_Examples +{ + public class StreamNetworkReaderExample : INetSharpExample + { + private const int PacketSize = 8192, ExpectedClientCount = 8; + public static readonly Encoding ServerEncoding = Encoding.UTF8; + public static readonly EndPoint ServerEndPoint = new IPEndPoint(IPAddress.Loopback, 12377); + + /// <inheritdoc /> + public string Name { get; } = "Stream Network Reader Example"; + + private static bool RequestHandler(in EndPoint remoteEndPoint, ReadOnlyMemory<byte> requestBuffer, int receivedRequestBytes, Memory<byte> responseBuffer) + { + requestBuffer.CopyTo(responseBuffer); + + lock (typeof(Console)) + { + Console.WriteLine($"Received {receivedRequestBytes} bytes from {remoteEndPoint}! Echoing back..."); + } + + return true; + } + + /// <inheritdoc /> + public Task RunAsync() + { + EndPoint defaultEndPoint = new IPEndPoint(IPAddress.Any, 0); + + Socket rawSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); + rawSocket.Bind(ServerEndPoint); + rawSocket.Listen(ExpectedClientCount); + + using StreamNetworkReader reader = new StreamNetworkReader(ref rawSocket, RequestHandler, defaultEndPoint, PacketSize, 100); + reader.Start(ExpectedClientCount); + + Console.WriteLine($"Started stream server at {ServerEndPoint}! Enter any key to stop the server..."); + Console.ReadLine(); + + reader.Stop(); + + rawSocket.Close(); + rawSocket.Dispose(); + + return Task.CompletedTask; + } + } +} +\ No newline at end of file diff --git a/NetSharp/NetSharpExamples/Examples/Stream Network Connection Examples/StreamNetworkWriterAsyncExample.cs b/NetSharp/NetSharpExamples/Examples/Stream Network Connection Examples/StreamNetworkWriterAsyncExample.cs @@ -0,0 +1,59 @@ +using NetSharp.Raw.Stream; + +using System; +using System.Net; +using System.Net.Sockets; +using System.Threading.Tasks; + +namespace NetSharpExamples.Examples.Stream_Network_Connection_Examples +{ + public class StreamNetworkWriterAsyncExample : INetSharpExample + { + private const int PacketSize = 8192; + + public static readonly EndPoint ClientEndPoint = new IPEndPoint(IPAddress.Loopback, 0); + + public static readonly EndPoint ServerEndPoint = StreamNetworkReaderExample.ServerEndPoint; + + /// <inheritdoc /> + public string Name { get; } = "Stream Network Writer Example (Asynchronous)"; + + /// <inheritdoc /> + public async Task RunAsync() + { + EndPoint defaultEndPoint = new IPEndPoint(IPAddress.Any, 0); + + Socket rawSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); + rawSocket.Bind(ClientEndPoint); + + using StreamNetworkWriter writer = new StreamNetworkWriter(ref rawSocket, defaultEndPoint, PacketSize); + await writer.ConnectAsync(ServerEndPoint); + + byte[] transmissionBuffer = new byte[PacketSize]; + + EndPoint remoteEndPoint = ServerEndPoint; + + while (true) + { + int sent = await writer.WriteAsync(remoteEndPoint, transmissionBuffer); + + lock (typeof(Console)) + { + Console.WriteLine($"Sent {sent} bytes to {remoteEndPoint}!"); + } + + int received = await writer.ReadAsync(remoteEndPoint, transmissionBuffer); + + lock (typeof(Console)) + { + Console.WriteLine($"Received {received} bytes from {remoteEndPoint}!"); + } + } + + await writer.DisconnectAsync(false); + + rawSocket.Close(); + rawSocket.Dispose(); + } + } +} +\ No newline at end of file diff --git a/NetSharp/NetSharpExamples/Examples/Stream Network Connection Examples/StreamNetworkWriterSyncExample.cs b/NetSharp/NetSharpExamples/Examples/Stream Network Connection Examples/StreamNetworkWriterSyncExample.cs @@ -0,0 +1,61 @@ +using NetSharp.Raw.Stream; + +using System; +using System.Net; +using System.Net.Sockets; +using System.Threading.Tasks; + +namespace NetSharpExamples.Examples.Stream_Network_Connection_Examples +{ + public class StreamNetworkWriterSyncExample : INetSharpExample + { + private const int PacketSize = 8192; + + public static readonly EndPoint ClientEndPoint = new IPEndPoint(IPAddress.Loopback, 0); + + public static readonly EndPoint ServerEndPoint = StreamNetworkReaderExample.ServerEndPoint; + + /// <inheritdoc /> + public string Name { get; } = "Stream Network Writer Example (Synchronous)"; + + /// <inheritdoc /> + public Task RunAsync() + { + EndPoint defaultEndPoint = new IPEndPoint(IPAddress.Any, 0); + + Socket rawSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); + rawSocket.Bind(ClientEndPoint); + + using StreamNetworkWriter writer = new StreamNetworkWriter(ref rawSocket, defaultEndPoint, PacketSize); + writer.Connect(ServerEndPoint); + + byte[] transmissionBuffer = new byte[PacketSize]; + + EndPoint remoteEndPoint = ServerEndPoint; + + while (true) + { + int sent = writer.Write(remoteEndPoint, transmissionBuffer); + + lock (typeof(Console)) + { + Console.WriteLine($"Sent {sent} bytes to {remoteEndPoint}!"); + } + + int received = writer.Read(ref remoteEndPoint, transmissionBuffer); + + lock (typeof(Console)) + { + Console.WriteLine($"Received {received} bytes from {remoteEndPoint}!"); + } + } + + writer.Disconnect(false); + + rawSocket.Close(); + rawSocket.Dispose(); + + return Task.CompletedTask; + } + } +} +\ No newline at end of file diff --git a/NetSharp/NetSharpExamples/NetSharpExamples.csproj b/NetSharp/NetSharpExamples/NetSharpExamples.csproj @@ -16,9 +16,4 @@ <ItemGroup> <ProjectReference Include="..\NetSharp\NetSharp.csproj" /> </ItemGroup> - - <ItemGroup> - <Folder Include="Examples\Datagram Network Connection Examples\" /> - <Folder Include="Examples\Stream Network Connection Examples\" /> - </ItemGroup> </Project> \ No newline at end of file diff --git a/NetSharp/NetSharpExamples/NetSharpExamples.xml b/NetSharp/NetSharpExamples/NetSharpExamples.xml @@ -40,6 +40,42 @@ <member name="M:NetSharpExamples.Benchmarks.Stream_Network_Connection_Benchmarks.StreamNetworkWriterSyncBenchmark.RunAsync"> <inheritdoc /> </member> + <member name="P:NetSharpExamples.Examples.Datagram_Network_Connection_Examples.DatagramNetworkReaderExample.Name"> + <inheritdoc /> + </member> + <member name="M:NetSharpExamples.Examples.Datagram_Network_Connection_Examples.DatagramNetworkReaderExample.RunAsync"> + <inheritdoc /> + </member> + <member name="P:NetSharpExamples.Examples.Datagram_Network_Connection_Examples.DatagramNetworkWriterAsyncExample.Name"> + <inheritdoc /> + </member> + <member name="M:NetSharpExamples.Examples.Datagram_Network_Connection_Examples.DatagramNetworkWriterAsyncExample.RunAsync"> + <inheritdoc /> + </member> + <member name="P:NetSharpExamples.Examples.Datagram_Network_Connection_Examples.DatagramNetworkWriterSyncExample.Name"> + <inheritdoc /> + </member> + <member name="M:NetSharpExamples.Examples.Datagram_Network_Connection_Examples.DatagramNetworkWriterSyncExample.RunAsync"> + <inheritdoc /> + </member> + <member name="P:NetSharpExamples.Examples.Stream_Network_Connection_Examples.StreamNetworkReaderExample.Name"> + <inheritdoc /> + </member> + <member name="M:NetSharpExamples.Examples.Stream_Network_Connection_Examples.StreamNetworkReaderExample.RunAsync"> + <inheritdoc /> + </member> + <member name="P:NetSharpExamples.Examples.Stream_Network_Connection_Examples.StreamNetworkWriterAsyncExample.Name"> + <inheritdoc /> + </member> + <member name="M:NetSharpExamples.Examples.Stream_Network_Connection_Examples.StreamNetworkWriterAsyncExample.RunAsync"> + <inheritdoc /> + </member> + <member name="P:NetSharpExamples.Examples.Stream_Network_Connection_Examples.StreamNetworkWriterSyncExample.Name"> + <inheritdoc /> + </member> + <member name="M:NetSharpExamples.Examples.Stream_Network_Connection_Examples.StreamNetworkWriterSyncExample.RunAsync"> + <inheritdoc /> + </member> <member name="T:NetSharpExamples.INetSharpExample"> <summary> Defines an example program. diff --git a/README.md b/README.md @@ -31,9 +31,9 @@ During a benchmark 1,000,000 packets are sent per client by default, with a data The RTT values measured are the very extremes of what you would get. When printing the RTT-per-packet, the maximum value is attained at the start of the connection and the minimum value seems to be sustained for the remainder of the connection. Again, your mileage may vary depending on the speed of your network, your packet loss (if using TCP), and the amount of packet processing you do on the server. The more processing you do, the longer your RTT times will be. -### Datagram Network Listener & Writer Benchmarks +### Datagram Network Reader & Writer Benchmarks The following is the datagram network listener (UDP) benchmark: -![Datagram Network Listener Benchmark][datagram-network-listener-benchmark] +![Datagram Network Reader Benchmark][datagram-network-reader-benchmark] ``` The worst performing client took 79911 ms to send all of their packets. @@ -60,9 +60,9 @@ Therefore, average RTT-per-packet: Time per packet: 3.8569x10^-5 (0.038569 ms) ``` -### Stream Network Listener & Writer Benchmarks +### Stream Network Reader & Writer Benchmarks The following is the stream network listener (TCP) benchmark: -![Stream Network Listener Benchmark][stream-network-listener-benchmark] +![Stream Network Reader Benchmark][stream-network-reader-benchmark] ``` The worst performing client took 93616 ms to send all of their packets. @@ -93,8 +93,8 @@ Therefore, average RTT-per-packet: [example-project]: docs/example-selector.png -[datagram-network-listener-benchmark]: docs/datagram-network-listener-benchmark.png +[datagram-network-reader-benchmark]: docs/datagram-network-reader-benchmark.png [datagram-network-writer-benchmark]: docs/datagram-network-writer-benchmark.png -[stream-network-listener-benchmark]: docs/stream-network-listener-benchmark.png +[stream-network-reader-benchmark]: docs/stream-network-reader-benchmark.png [stream-network-writer-benchmark]: docs/stream-network-writer-benchmark.png diff --git a/docs/datagram-network-listener-benchmark.png b/docs/datagram-network-reader-benchmark.png Binary files differ. diff --git a/docs/stream-network-listener-benchmark.png b/docs/stream-network-reader-benchmark.png Binary files differ.