Was ist der aktuelle Standard für die Implementierung eines asynchronen Socket-Clients?

8

Ich suche nach den Best Practices, um die folgenden Anforderungen zu erfüllen:

  • Ein Framework, das mehrere Client-Sockets asynchron verarbeitet
  • Jedes eingehende Nachrichtenprotokoll schreibt vor, dass jede Nachricht eine Formatzeichenfolge hat und mit einem Zeilenvorschubzeichen '\ n' markiert ist.
  • Ich habe die volle Kontrolle über die Client-Seite, aber nicht über die Server-Seite. Server akzeptiert und sendet stringbasierte Nachrichten mit Zeilenvorschubzeichen, um den Abschluss der Nachricht zu markieren.
  • Ich möchte jederzeit über jeden verbundenen Socket Nachrichten senden können (jeder Socket kann Nachrichten empfangen und senden).
  • Eingehende Nachrichten sollten über einen Rückruf weitergeleitet werden.
  • Ich möchte in meiner Implementierung auswählen können, ob alle eingehenden Nachrichten von allen verbundenen Sockets an einen einzelnen Callback weitergeleitet werden oder ob jeder Socket-Client seinen eigenen Callback implementiert.
  • Ich verbinde maximal 4 Clients / Sockets. Also suche ich nach Vorschlägen, die aus solchen begrenzten Mengen von Sockets Kapital schlagen, die jedoch alle gleichzeitig verwalten können.

Ich frage mich, ob das Framework, in dem ich BeginReceive und EndReceive mit implementiertem IAsyncResult-Callback verwende, Stand der Technik ist, wenn ich auf .NET 4.5 ziele. Gibt es eine bessere Lösung, z. B. die Verwendung von NetworkStream oder andere API-Optionen? Was mich wirklich mit der BeginReceive / EndReceive-Implementierung stört ist, dass ich nach EndReceive wieder BeginReceive aufrufen muss und den Rückruf erneut registrieren muss. Das klingt für mich nach einem schrecklichen Aufwand. Warum können neue Daten zu keinem Zeitpunkt async hinzugefügt werden und gleichzeitig ein anderer Kontext vollständige Nachrichten erstellen, die dann durch ein erhöhtes Ereignis geleitet werden?

Das Argument der Verwendung von IAsyncResult wird oft dadurch gegeben, dass die Thread-Behandlung erledigt ist, aber was gegen folgendes spricht: Einen NetworkStream verwenden und einfach vom Stream lesen und schreiben. Wie erwähnt, werden nur String-Nachrichten ausgetauscht und jede Nachricht pro Protokoll wird durch das Zeilenvorschubzeichen als abgeschlossen markiert. Ein separater Task / Thread würde einen Streamreader (basierend auf dem Netzwerkstream) durch ReadLine() abfragen. Es kann wahrscheinlich nicht einfacher werden, oder?

Was ich im Grunde frage ist, wie kann der folgende Code wirklich async gemacht werden?

%Vor%     
Matt Wolf 24.02.2013, 07:05
quelle

2 Antworten

11

Derzeit gibt es keinen aktuellen Standard oder eine gängige Praxis. Sie haben eine Reihe von Möglichkeiten mit Vor- und Nachteilen:

  1. Wickeln Sie die TAP-Methoden in Task s und verwenden Sie async / await .
    • Vorteile: Ziemlich einfach zu tun.
    • Nachteile: Es ist Low-Level; Sie müssen alle verschiedenen async -Operationen selbst in einer "unendlichen" Schleife verwalten und die Zustandsverwaltung für jede Verbindung verwalten.
  2. Wickeln Sie die Socket *Async Methoden in Task s und verwenden Sie sie async / await .
    • Vorteile: Geschwindigkeit. Dies ist die schnellste und am besten skalierbare Option.
    • Nachteile: Sie haben immer noch Low-Level- "unendliche" Schleifen und Zustandsverwaltung, wo der Code komplexer als Option (1) ist.
  3. Wandeln Sie Socket-Vervollständigungen in Rx-Ereignisse um.
    • Vorteile: Sie können die "unendlichen" Schleifen kapseln und die Vervollständigungen als einen Strom von Ereignissen behandeln.
    • Nachteile: Es gibt eine heftige Lernkurve für Rx, und dies ist kein einfacher Anwendungsfall. Das Verwalten des Status jeder Verbindung kann komplex werden.
  4. Konvertieren Sie Socket-Vervollständigungen in TPL Dataflow .
    • Vorteile: (wie Rx): Kapselung der Schleifen und Erhalt eines Datenstroms.
    • Nachteile: Die Lernkurve ist einfacher als Rx, aber Sie haben immer noch eine komplexe Zustandsverwaltung für jede Verbindung.
  5. Verwenden Sie eine vorhandene Bibliothek, z. B. meine Nito.Async Bibliothek, die EAP Socket-Klassen.
    • Vorteile: Sehr einfach zu bedienen; Alles ist ein Event und es gibt keine Probleme mit Multithreading. Außerdem werden die Tricker-Teile der Statusverwaltung für Sie erledigt.
    • Nachteile: Skaliert nicht so gut wie die untergeordneten Lösungen.

Für Ihre Situation (einige hundert Nachrichten pro Sekunde auf weniger als einhundert Sockets) würde ich meine Nito.Async-Bibliothek empfehlen. Es ist die einfachste dieser Optionen, um zu arbeiten.

In Bezug auf Ihr Protokoll müssen Sie die \n s von Hand analysieren und Ihre Pufferung selbst durchführen. (Das gilt für alle oben genannten Optionen.)

    
Stephen Cleary 25.02.2013, 17:30
quelle
1

Gemäß meiner Empfehlung verwenden Sie bitte die neue Async-Form von XXXReceive und 'XXXSend' (wobei XXX für Begin und End steht), die neuen verfügbaren Methoden sind ReceiveAsync und SendAsync Methoden, die SocketAsyncEventArgs , um den Socket und andere Informationen zu den Callback-Event-Handlern zu übergeben.

Ich hatte ein gutes funktionierendes Beispiel von Socket-Client und -Server im msdn-Archiv gesehen, das bis zu 500 Verbindungen skalierbar war (wie ich es in einer der Projektanpassungen davon getestet hatte), aber derzeit kann ich den Link vom googlen nicht finden. Aber hier ist ein weiterer Link von msdn Archiv zum gleichen Thema hoffentlich wird es Ihnen helfen - Holen Sie sich näher an die Wire mit leistungsstarken Sockets in .NET ..

AKTUALISIEREN

Zunächst kann ich Ihnen nur eine Idee für die endgültige Implementierung und wenn möglich einige kurze Beispielcode-Snippets geben. ok hier geh ich mit mehr Details

Ich denke, Sie können zum Link des letzten Absatzes springen. ;)

Lassen Sie mich einmal hervorheben, weil ich möchte, ich sagte SendAsync und ReceiveAsync nicht BeginReceive/EndReceive und BeginSend/EndSend , d. h. Event-based Async Pattern (EAP)

  

Der Vorteil der asynchronen Form der Socket-Methoden besteht darin, dass es sich um einen ausnahmslosen Ansatz für die Socket-Programmierung handelt, der sich schneller als BeginSend / EndSend-Methoden erweisen kann.

Hier ist der Link für das Beispiel, von dem ich herausgefunden habe, dass es bis zu 500 PARALLEL-Verbindungen nützlich ist - Netzwerkbeispiele für .NET v4.0

Sie müssen die Funktion "Warten / Asynchron" von .NET 4.5 verwenden. Hier ist das .NET 4.5 Code-Snippet, das die Verwendung von WebSocket class zeigt, welches auch an Socket implements angepasst werden kann - Unterstützung für das WebSockets-Protokoll (Ich vermute, WebSockets AspNetWebSocketContext wird Sockets SocketAsyncEventArgs sein)

Ich habe Warten auf Socket-Operationen Beispielcode von gefunden MSDN - Parallel Programming-Team-Blog , das zur Implementierung von "wait / async" aus .NET 4.5 Framework nützlich sein kann.

Ich hoffe, dies erweist sich als hilfreich für Sie.

    
Harsh Baid 25.02.2013 05:54
quelle