Wir haben einen Anwendungsserver, der mit Delphi 2010 und Indy 10 entwickelt wurde. Dieser Server erhält mehr als 50 Anfragen pro Sekunde und funktioniert gut. Aber in manchen Fällen scheint Indy sehr dunkel zu sein. Ihre Komponenten sind gut, aber manchmal habe ich mich in den Quellcode vertieft, nur um eine einfache Sache zu verstehen. Indy fehlt es an guter Dokumentation und guter Unterstützung.
Die letzte Sache, die ich fand, war ein großes Problem für mich: Ich muss feststellen, wenn ein Client nicht anmutig trennt (wenn der Client zum Absturz oder zum Herunterfahren, zum Beispiel, dem Server nicht sagen, dass es trennen wird) und Indy konnte nicht TU das. Wenn ich das will, muss ich einen Algorithmus wie Heartbeat, Pooling oder TCP Keep-Alive entwickeln. Ich möchte nicht mehr Zeit damit verbringen, einen Job zu machen, wie ich zumindest denke. Nach ein paar Studien habe ich herausgefunden, dass dies nicht Indys Fehler ist, aber dies ist ein Problem aller blockierenden Sockelkomponenten.
Jetzt denke ich wirklich daran, den Kern des Servers in eine andere gute Suite zu verwandeln. Ich muss zugeben, dass ich dazu tendiere, eine nicht blockierende Steckdose zu benutzen. Auf dieser Grundlage habe ich einige Fragen:
BEARBEITEN
Ich denke, manche Leute verstehen nicht, was ich will. Ich möchte keinen eigenen Socket erstellen. Ich habe lange mit Sockeln gearbeitet und ich habe es satt. Wirklich.
Und nicht blockierende Sockets können Client-Disconnects erkennen. Das ist eine Tatsache und es hat eine gute Dokumentation über das Internet. Ein nicht blockierender Socket prüft ständig den Socket-Status auf neue eingehende Daten und ermöglicht die Erkennung, dass der Socket ungültig ist. Dies ist kein Heartbeat-Algorithmus. Ein Heartbeat-Algorithmus wird auf der Client-Seite verwendet und sendet regelmäßig Pakete (auch Keep-Alive genannt) an den Server, um zu sagen, dass er noch lebt.
BEARBEITEN
Ich mache es mir nicht klar. Vielleicht, weil Englisch nicht meine Hauptsprache ist. Ich sage nicht, dass es möglich ist, eine unterbrochene Verbindung zu erkennen, ohne zu versuchen, Daten von einem Socket zu senden oder zu empfangen. Was ich sage, ist, dass jeder nicht blockierende Socket das kann, weil er ständig versucht, aus dem Socket nach neuen eingehenden Daten zu lesen. Warum ist das so schwer zu verstehen? Wenn ihr ip * -Demos herunterlädt und ausführt, dann könnt ihr die Echolvers- und Echoclient-Tests (beide benutzen TCP) selbst testen. Ich habe es bereits getestet und es funktioniert so, wie ich es erwartet hatte. Selbst wenn Sie den alten TCPSocketServer und TCPSocketClient in einem nicht-blockierenden Modus verwenden, werden Sie sehen, was ich meinte.
"Was hat einen Vorteil beim Wechsel von blockierenden zu nicht blockierenden Sockets?
Kann ich Client-Verbindungsunterbrechungen (nicht anmutig) erkennen? "
Nur meine zwei Cent, um bei dieser Frage den Ball ins Rollen zu bringen - ich bin kein EXPERTE, aber ich habe eine Menge Erfahrung mit ihnen. Wenn ich mich irre, bin ich mir sicher, dass mich jemand korrigieren wird ... :-)
Ich nehme an, da Sie einen Server mit blockierenden Sockets mit 50 Verbindungen pro Sekunde betreiben, haben Sie einen Threading-Mechanismus, um Client-Anfragen zu bearbeiten. Wenn das der Fall ist, können Sie nichts von nicht blockierenden Sockets gewinnen. Im Gegenteil - Sie müssen Ihre Serverlogik ändern, um ereignisgesteuert zu sein - basierend auf Ereignissen, die in Ihrem Hauptthread von den nicht blockierenden Sockets ausgelöst werden, oder verwenden Sie das konstante Polling, um zu wissen, was Ihre Sockets vorhaben.
Nicht-blockierende Sockets können nicht erkennen, dass Clients die Verbindung ohne Benachrichtigung trennen, genauso wenig wie blockierende Sockets - sie haben keine telepathischen Kräfte ... Die Art der TCP / IP-Konversation zwischen Client und Server ist dieselbe - Blockieren und Nicht-Blockieren bezieht sich nur auf die Interaktion Ihrer Anwendung mit der Socket-Verbindung, die die "Konversation" ausführt.
Wenn Sie tote Verbindungen bereinigen müssen, müssen Sie einen Heartbeat- oder Timeout-Mechanismus für Ihren Socket implementieren (ich habe noch nie eine moderne Socket-Implementierung gesehen, die Timeouts nicht unterstützt).
Was bringt der Wechsel von blockierenden zu nicht blockierenden Sockets?
Erhöhte Geschwindigkeit, Verfügbarkeit und Durchsatz (aus meiner Erfahrung). Ich hatte einen IndySockets-Client, der ungefähr 15 Anfragen pro Sekunde erhielt, und als ich direkt zu asynchronen Sockets ging, stieg der Durchsatz auf ungefähr 90 Anfragen pro Sekunde (auf demselben Rechner). In einem separaten Benchmarktest auf einem Server in einem Rechenzentrum mit einer 30 Mbit Verbindung konnte ich mehr als 300 Anfragen pro Sekunde bekommen.
Kann ich Client-Verbindungsunterbrechungen (nicht ordnungsgemäß) erkennen?
Das war eine Sache, die ich noch nicht ausprobieren musste, da mein gesamter Code auf der Clientseite war.
Welche Komponentensuite hat das beste Produkt? Mit dem besten Produkt meine ich: schnell, guten Support, gute Tools und einfach zu implementieren.
Sie können Ihren eigenen Socket-Client in ein paar Tagen erstellen und er kann sehr robust und schnell sein ... viel schneller als die meisten Sachen, die ich "von der Stange" gesehen habe. Sehen Sie sich meinen asynchronen Socket-Client an: Ссылка
Aktualisierung:
(Per Mikey's Kommentare)
Ich bitte Sie um eine generische, technische Erklärung, wie NBS den Durchsatz im Gegensatz zu einem richtig entworfenen BS-Server erhöht.
Nehmen wir als Beispiel einen Server mit hoher Auslastung: Sagen wir, dass Ihr Server 1000 Verbindungen zu einem bestimmten Zeitpunkt verwalten soll, mit blockierenden Sockets müssten Sie 1000 Threads erstellen, und selbst wenn sie größtenteils im Leerlauf sind, wird die CPU still verbringen viel Zeit Kontextwechsel. Wenn die Anzahl der Clients steigt, müssen Sie die Anzahl der Threads erhöhen, um mithalten zu können, und die CPU wird unvermeidlich die Kontextumschaltung erhöhen. Für jede Verbindung, die Sie mit einem blockierenden Socket aufbauen, werden Sie den Overhead des Launchs eines neuen Threads auf sich nehmen und Sie werden schließlich den Aufwand für die Bereinigung nach dem Thread aufbringen. Natürlich ist das erste, was einem einfällt: Warum nicht den ThreadPool verwenden, Sie können die Threads wiederverwenden und den Overhead beim Erstellen / Bereinigen von Threads reduzieren.
Hier ist, wie dies unter Windows gehandhabt wird (daher die .NET-Verbindung): sicher, aber das erste, was Sie mit dem .NET ThreadPool bemerken werden, ist, dass es zwei Arten von Threads gibt und es kein Zufall ist: Benutzer-Threads und E / A-Completion-Port-Threads. Asynchrone Sockets verwenden die IO-Completion-Ports, die es "einem einzelnen Thread ermöglichen, gleichzeitige E / A-Operationen für verschiedene Handles oder sogar gleichzeitige Lese- und Schreiboperationen für denselben Handle auszuführen." ( 1 ) Die E / A-Completion-Port-Threads wurden speziell entwickelt, um E / A effizienter zu verarbeiten als Sie könnten jemals erreichen, wenn Sie die Benutzer-Threads in ThreadPool verwendet haben, es sei denn, Sie haben Ihren eigenen Kernel-Modus-Treiber geschrieben .
"Der Completion-Port verwendet ein spezielles Voodoo, um sicherzustellen, dass nur eine bestimmte Anzahl von Threads gleichzeitig ausgeführt werden kann. Wenn ein Thread im Kernel-Modus blockiert, wird automatisch ein weiterer gestartet." (2 )
Es gibt noch weitere Vorteile: "Zusätzlich zu dem nicht blockierenden Vorteil der überlappenden Socket-E / A ist der andere Vorteil eine bessere Leistung, da Sie eine Pufferkopie zwischen dem TCP-Stapelpuffer und dem Benutzerpuffer für jede E / A speichern Anruf." ( 3 )
Ich verwende Indy und Synapse TCP-Bibliotheken mit guten Ergebnissen seit einigen Jahren und tat es nicht finde irgendwelche Showstopper in ihnen. Ich benutze die Bibliotheken in Threads - Client und Server Seite, Stabilität und Leistung war kein Problem. (Sechstausend Anfragen und Antwortnachrichten pro Sekunde und mehr mit dem Server, der auf demselben System ausgeführt wird, sind typisch.)
Blocking-Sockets sind sehr nützlich, wenn das Protokoll weiter fortgeschritten ist als ein einfacher 'String senden / String empfangen'. Nicht blockierende Sockets verursachen eine höhere Kopplung von Nachrichtenprotokollhandlern mit der Socket-Lese- / Schreiblogik, so dass ich mich schnell von nicht blockierendem Code entfernte.
Keine Bibliothek kann die Einschränkungen des TCP / IP-Protokolls hinsichtlich der Erkennung von Verbindungsverlusten überwinden. Nur wenn Sie versuchen, Daten zu lesen oder zu senden, können Sie feststellen, ob die Verbindung noch vorhanden ist.
In Windows gibt es eine dritte Option, bei der es sich um überlappende E / A handelt. Nicht blockierende Sockets sind essentiell für ein Modell, das Windows-Nachrichten verwendet, die entwickelt wurden, um zu verhindern, dass GUI-Apps mit einem Thread während des Wartens auf Daten "blockiert" werden. Eine moderne Anwendung IMHO würde besser mit Threads und überlappenden I / O entworfen werden.
Siehe zum Beispiel Ссылка
Aahhrrgghh - der Mythos, immer wieder "verlorene" Verbindungen entdecken zu können. Wenn Sie eine Maschine mit einer Clientverbindung einschalten, kann der Server ohne Senden von Daten nicht feststellen, dass die Verbindung "tot" ist. Das ist durch das Design des TCP-Protokolls. Nehmen Sie mein Wort dafür nicht - lesen Sie diesen Artikel ( Erkennung von halboffenen (dropped) TCP / IP-Socket-Verbindungen ).
In diesem Artikel werden die Hauptunterschiede zwischen Blockieren und Nicht-Blockieren erläutert:
Einführung in Indy, von Chad Z. Hower
Vorteile der Blockierung
- Einfach zu programmieren - Das Blockieren ist sehr einfach zu programmieren. Alle Benutzercodes können an einem Ort existieren, und in einem Reihenfolge.
- Einfache Portierung auf Unix - Da Unix blockierende Sockets verwendet, ist portabler Code erforderlich kann leicht geschrieben werden. Indy nutzt dies Tatsache, um seine einzige Quelle zu erreichen Lösung.
- Gut in Threads arbeiten - Da blockierende Sockets sequenziell sind sind inhärent verkapselt und daher sehr leicht in Threads verwendet.
Nachteile der Blockierung
- Benutzeroberfläche "Freeze" mit Clients - Blocking Socket-Aufrufe nicht zurück, bis sie es geschafft haben ihre Aufgabe. Wenn solche Anrufe getätigt werden im Hauptthread einer Anwendung, Die Anwendung kann die Benutzerschnittstellenmeldungen. Dies bewirkt die Benutzeroberfläche zu "frieren" weil das Update, Repaint und andere Nachrichten kann erst nach der Sperrung bearbeitet werden Socket - Aufrufe geben die Kontrolle an die Anwendungen Nachrichtenverarbeitungsschleife.
Er schrieb auch:
Blockierung ist NICHT böse
Blocking Sockets wurden wiederholt ohne Haftbefehl angegriffen. Gegensätzlich zu populärer Glaube, blockierende Sockel sind nicht böse.
Es ist nicht an issue of all blocking sockets components
, dass sie keine Client-Verbindung erkennen können. Es gibt einen no technischen Vorteil auf der Seite nicht blockierender Komponenten in diesem Bereich.
Tags und Links sockets delphi components