Ich brauche einen TCP-Server unter Verwendung von C# .NET 4.5+
Nun zu bauen, das erste, was zu bestimmen ist, ob es basen Knochen TCP/IP sein muss. Wenn Sie möglicherweise können, schreiben Sie eine, die eine höhere Abstraktion verwendet, wie SignalR oder WebAPI. Wenn Sie einen mit WebSockets (SignalR) schreiben können, tun Sie das und schauen Sie niemals zurück.
Ihre Schlussfolgerungen klingen ziemlich gut. Nur ein paar Anmerkungen:
SocketAsyncEventArgs - Ist komplex und wirklich nur für sehr große Systeme benötigt, BTW was ein sehr großes System ausmacht? :-)
Es ist nicht so sehr ein "großes" System in Bezug auf die Anzahl der Verbindungen. Es ist eher eine Frage, wie viel Verkehr im System ist - die Anzahl der Lese-/Schreibvorgänge pro Sekunde.
Die einzige Sache, die SocketAsyncEventArgs
tut, ist, Ihre E/A-Strukturen wiederverwendbar zu machen. Die/End*
() APIs erstellen eine neue IAsyncResult
für jede E/A-Operation, und dies kann Druck auf den Garbage Collector verursachen. SocketAsyncEventArgs
ist im Wesentlichen das gleiche wie IAsyncResult
, nur es ist wiederverwendbar. Beachten Sie, dass es einige Beispiele gibt, die die SocketAsyncEventArgs
APIs ohne verwenden, die die SocketAsyncEventArgs
Strukturen wiederverwenden, die völlig lächerlich ist.
Und es gibt keine Richtlinien hier: schwerere Hardware wird die APM-APIs für viel mehr Verkehr verwenden können. In der Regel sollten Sie einen Barebone-APM-Server erstellen und zuerst einen Test durchführen und erst dann zu SAEA wechseln, wenn er auf der Hardware des Zielservers nicht funktioniert.
Auf die Fragen:
Sollte verwende ich eine Manual wenn sie mit der TCP-Client-Sammlung interagieren? Ich nehme an, dass die Asyc-Ereignisse den Zugriff auf diese Sammlung sperren müssen.
Wenn Sie TAP -basierte Wrapper verwenden, wieder await
wird dann auf einem erfassten Kontext standardmäßig. Ich erkläre das in my blog post on async
/await
.
Es gibt ein paar Ansätze, die Sie hier nehmen können. Ich habe erfolgreich einen zuverlässigen und performanten single-threaded TCP/IP-Server geschrieben; das Äquivalent für modernen Code wäre, etwas wie my AsyncContextThread
class zu verwenden. Es stellt einen Kontext bereit, der dazu führt, dass await
standardmäßig auf demselben Thread fortgesetzt wird.
Das Schöne an Single-Thread-Servern ist, dass es nur einen Thread gibt, so dass keine Synchronisation oder Koordination notwendig ist. Ich bin mir jedoch nicht sicher, wie gut ein Single-Thread-Server skalieren würde. Vielleicht möchten Sie es ausprobieren und sehen, wie viel Ladung es aufnehmen kann. Wenn Sie mehrere Threads benötigen, können Sie einfach async
Methoden im Thread-Pool verwenden. await
hat keinen erfassten Kontext und wird daher in einem Threadpool-Thread fortgesetzt. In diesem Fall müssten Sie den Zugriff auf alle gemeinsam genutzten Datenstrukturen einschließlich Ihrer TCP-Client-Sammlung koordinieren.
Beachten Sie, dass SignalR das alles für Sie übernimmt. :)
Die beste Möglichkeit, einen getrennten Client zu erkennen, nachdem ich BeginReceive aufgerufen habe. Ich habe festgestellt, dass der Anruf feststeht und auf eine Antwort wartet, damit diese bereinigt werden muss.
Dies ist die half-open problem, die ich ausführlich auf meinem Blog diskutiere. Der beste Weg (IMO), dies zu lösen, besteht darin, periodisch eine "Noop" -Freiheitsmeldung an jeden Client zu senden.
Wenn das Ändern des Protokolls nicht möglich ist, ist die nächstbeste Lösung, die Verbindung nach einem Timeout ohne Kommunikation zu schließen. So entscheiden sich HTTP- "persistent" -/"keep-alive" -Verbindungen zu schließen. Es gibt eine andere mögliche Lösung (Ändern der Keepalive-Paket-Einstellungen auf dem Socket), aber es ist nicht so einfach (erfordert p/Invoke) und hat andere Probleme (nicht immer von Routern, nicht von allen OS TCP/IP-Stacks, etc. unterstützt).
Oh, und SignalR wird dies für Sie behandeln. :)
Senden von Nachrichten an einen bestimmten TCP-Client. Ich denke, Funktion in benutzerdefinierten TCP-Sitzungsklasse, um eine Nachricht zu senden. Muss ich in einem asynchronen Modell einen zeitgesteuerten Prozess erstellen, der eine Nachrichtenwarteschlange prüft, oder würde ich ein Ereignis in einer TCP-Sitzungsklasse erstellen, die Zugriff auf den TcpClient und den zugehörigen Stream hat? Wirklich interessiert an Meinungen hier.
Wenn Ihr Server kann Nachrichten an einen Client (dh es ist nicht nur ein Request/Response-Protokoll, ein Teil des Servers kann ohne den Client jeden Client um Nachrichten senden ein Update anfordern), dann ja, Sie Sie benötigen eine ordnungsgemäße Warteschlange mit ausgehenden Anfragen, da Sie mehrere gleichzeitige Schreibvorgänge auf einem Socket nicht (zuverlässig) ausführen können. Ich möchte, dass der Verbraucher nicht timerbasiert ist. Es sind Async-kompatible Producer/Consumer-Warteschlangen verfügbar (wie BufferBlock<T>
from TPL Dataflow und it's not that hard to write one, wenn Sie async-compatible locks and condition variables haben).
Oh, und SignalR wird dies für Sie behandeln. :)
Ich möchte einen Thread für den gesamten Dienst verwenden und nicht blockierende Prinzipien innerhalb gibt es anythings ich sollte bewusst sein espcially in Zusammenhang mit der 1. Manual etc ..
Wenn Ihr gesamter Dienst single-threaded ist, sollten Sie überhaupt keine Koordinationsprimitiven benötigen. Wenn Sie jedoch den Thread-Pool verwenden, anstatt ihn aus Gründen der Skalierbarkeit mit dem Hauptthread zu synchronisieren, müssen Sie ihn koordinieren. Ich habe eine coordination primitives library, die Sie nützlich finden können, da ihre Typen synchrone und asynchrone APIs haben. Dies ermöglicht beispielsweise, dass eine Methode an einer Sperre blockiert, während eine andere Methode eine Sperre asynchron blockieren kann.
Sie haben vielleicht ein wiederkehrendes Thema um SignalR bemerkt. Verwenden Sie es, wenn Sie können! Wenn Sie müssen schreiben Sie einen unverhofften TCP/IP-Server und kann nicht SignalR verwenden, dann nehmen Sie Ihre ursprüngliche Zeit schätzen und verdreifachen. Ernst. Dann kannst du mit meiner TCP/IP FAQ blog series den Pfad des schmerzhaften TCP beginnen.
Suchen Sie im Internet nach "IO Completion Ports .NET" – selbie
@selbie Entschuldigung, da ich vielleicht nicht klar gewesen bin, möchte ich dies in C# tun. Haben Sie vorgeschlagen, dass ich C++ oder die in .NET implementierten IOCP-Konzepte verwende, dachte ich, dass es in .NET 4.5 einfachere und leistungsfähigere Alternativen geben würde. Es gibt ein Codeprojektbeispiel, das dies tut, aber ich dachte wieder, dass der Event/Task-gesteuerte Ansatz ausreichen würde. – Nicholas
Alle asynchronen Socket-APIs verwenden bereits einen IOCP. –