TcpSharpr - Eine kleine Networking Library

    • Release
    • Open Source

    Es gibt 3 Antworten in diesem Thema. Der letzte Beitrag () ist von OPTiX.

      TcpSharpr - Eine kleine Networking Library

      TcpSharpr
      TcpSharpr ist eine kleine in C# geschriebene Networking-Library, die ich erstellt habe um schnell und einfach mit anderen .NET Anwendungen zu reden. Bei der Erstellung der Library habe ich darauf geachtet sie so "straight-forward" zu machen wie möglich. Zur Verwendung wird kein großes Wissen von TCP benötigt.

      Zurzeit bietet diese Library keine Implementierung für verschlüsselten Datenverkehr und eine sinnvolle Implementierung für große Datenübertragungen.
      Beide diese Dinge möchte ich jedoch in einem zukünftigen Build anstreben.

      Mindestanforderungen
      Zur Verwendung wird mindestens NET Core 2.0 benötigt.

      Source-Code
      Diese Library ist open-source. Der Source-Code ist zu finden unter github.com/RyanTT/TcpSharpr

      Verwendungsbeispiele

      Spoiler anzeigen
      Wie erstelle ich einen Server?

      C#-Quellcode

      1. Server server = new Server(new IPEndPoint(IPAddress.Parse("127.0.0.1"), 1805));
      2. server.Start();


      Wie erstelle ich einen Client und verbinde mit einem Server?

      C#-Quellcode

      1. Client client = new Client(new IPEndPoint(IPAddress.Parse("127.0.0.1"), 1805));
      2. await client.ConnectAsync();


      Wie erstelle ich eine Methode zum Aufruf über das Netzwerk?

      Synchron

      C#-Quellcode

      1. public int RemoteAddition(int a, int b) {
      2. return a + b;
      3. }
      4. server.CommandManager.RegisterCommand("AddNumbers", new Func<int, int, int>(RemoteAddition));


      Asynchron

      C#-Quellcode

      1. public static async Task<string> DownloadHtml(string url) {
      2. return await new WebClient().DownloadStringTaskAsync(url);
      3. }
      4. server.CommandManager.RegisterAsyncCommand("DownloadHtml", new Func<string, Task<string>>(DownloadHtml));


      Wie führe ich eine Methode übers Netzwerk aus und erhalte den Rückgabewert?

      C#-Quellcode

      1. var additionRequest = await client.SendRequestAsync("AddNumbers", 5, 10);
      2. int result = await additionRequest.GetResultAsync<int>(); // result = 15


      oder wenn man sich für das Resultat der Funktion nicht interessiert...

      C#-Quellcode

      1. await client.SendRequestAsync("AddNumbers", 5, 10);



      Einen Server entweder nach der UTC oder der lokalen Zeit zu fragen könnte zum Beispiel so aussehen:

      C#-Quellcode

      1. using System;
      2. using System.Net;
      3. using System.Threading.Tasks;
      4. namespace TcpSharpr.Example {
      5. class Program {
      6. static void Main(string[] args) {
      7. MainAsync().Wait();
      8. }
      9. static DateTime GetServerTime(bool utc) {
      10. if (utc) {
      11. return DateTime.UtcNow;
      12. } else {
      13. return DateTime.Now;
      14. }
      15. }
      16. static async Task MainAsync() {
      17. Server server = new Server(new IPEndPoint(IPAddress.Parse("127.0.0.1"), 1805));
      18. server.CommandManager.RegisterCommand("GetServerTime", new Func<bool, DateTime>(GetServerTime));
      19. server.Start();
      20. Client client = new Client(new IPEndPoint(IPAddress.Parse("127.0.0.1"), 1805));
      21. await client.ConnectAsync();
      22. bool getUtc = true;
      23. var serverTimeRequest = await client.SendRequestAsync("GetServerTime", getUtc);
      24. Console.WriteLine($"The server time (UTC: {getUtc}) is " + await serverTimeRequest.GetResultAsync<DateTime>());
      25. Console.ReadLine();
      26. }
      27. }
      28. }


      Für (Verbesserungs-)Vorschläge bin ich immer dankbar.

      OPTiX schrieb:

      Für (Verbesserungs-)Vorschläge bin ich immer dankbar.
      Habs nicht probiert, aber das Konzept denkt immerhin so weit, einen Mechanismus zur Festlegung eines BefehlsProtokolls bereitzustellen.
      Es scheint mir aber ein nur unidirektionales BefehlsProtokoll - also Clients können dem Server befehlen, aber nicht annersrum.
      Also ungefähr ist hier gebastelt, was Remoting oder Wcf so leisten: Ein Server empfängt Nachrichten und antwortet dem, der gefragt hat.

      Aber beispielweise bei einem Chat muss glaub auch der Server Befehle an die Clients senden können.
      Weil wenn Chatter A den Chatter B ansprechen will, kann ja nicht gewartet werden, bis Chatter B den Befehl zum Abruf der Nachricht sendet.
      Sondern der Server muss initiativ werden können, und von sich aus die Nachricht an B zustellen können.

      Guck - u.a. zum bidirektionalen BefehlsProtokoll hab ich mich hier ausgemährt: TcpKommunikation + Networkstream

      Ein anneres Problem, was du evtl. hast sind komplexe Datentypen: Kann dein Server solch zurückgeben, etwa Datensätze mit allen möglichen Properties?
      Vollzitat entfernt. ~Trade
      Das ist wohl den Beispielen verschuldet, in denen es leider nicht gezeigt wird. Bidirektionale Kommunikation ist mit der Library auch möglich. Hier ein Beispiel, in dem es verwendet wird:

      C#-Quellcode

      1. using System;
      2. using System.Net;
      3. using System.Threading.Tasks;
      4. using TcpSharpr.Network;
      5. namespace TcpSharpr.Testing {
      6. public class Example2 {
      7. public static async Task Run() {
      8. Server server = new Server(new IPEndPoint(IPAddress.Parse("127.0.0.1"), 1805));
      9. server.CommandManager.RegisterCommand("BroadcastToAll", new Action<NetworkClient, string>(ServerBroadcastToAll));
      10. server.Start();
      11. Client client = new Client(new IPEndPoint(IPAddress.Parse("127.0.0.1"), 1805));
      12. client.CommandManager.RegisterCommand("WriteToConsole", new Action<string>(Console.WriteLine));
      13. await client.ConnectAsync();
      14. await client.SendAsync("BroadcastToAll", "Hallo!");
      15. Console.ReadLine();
      16. }
      17. static void ServerBroadcastToAll(NetworkClient context, string message) {
      18. Server server = context.GetParent();
      19. var allClients = server.ConnectedClients;
      20. foreach (var client in allClients) {
      21. Task a = client.SendAsync("WriteToConsole", $"{context.Endpoint.ToString()}: {message}");
      22. }
      23. }
      24. }
      25. }


      Bzgl. der Übertragung von komplexen Datentypen: Da ich intern den BinaryFormatter verwende, sollte es meines Wissens nach möglich sein alle komplexen Datentypen zu übertragen, welche auf beiden Seiten unter dem gleichen qualifizierten Pfad vorhanden sind.
      Da würde sich dann z.B. eine "Contract"-Library zwischen beiden Seiten anbieten.

      Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Trade“ ()

      Ich habe der Library jetzt noch die Möglichkeit gegeben Streams als Parameter zu übertragen.
      Der Vorteil hierin liegt, dass größere Datenmengen damit übertragen werden können, ohne den weiteren Paketverlauf zu stören bzw. jegliche andere Kommunikation zu blockieren.

      Das Senden von Streams ist so einfach wie:

      C#-Quellcode

      1. FileStream fileStream = new FileStream(@"C:\Users\timet\Desktop\dotnet-sdk-2.1.201-win-x64.exe", FileMode.Open);
      2. var request = await client.SendAsync("StreamTransmission", fileStream);


      Lesen aus einem übertragenen Stream geht wie folgt:

      C#-Quellcode

      1. private static async Task StreamTransmission(SegmentedNetworkStream segmentedNetworkStream) {
      2. while (!segmentedNetworkStream.DataComplete || segmentedNetworkStream.DataAvailable > 0) {
      3. byte[] buffer = new byte[1048576];
      4. // Wait until (partial) data has been transmitted and is ready to be used
      5. long dataAvailable = await segmentedNetworkStream.WaitUntilDataAvailable();
      6. int bytesRead = await segmentedNetworkStream.ReadAsync(buffer, 0, buffer.Length);
      7. }
      8. }


      Eine ausführlichere Erklärung ist in der GitHub Readme vorhanden.