![]() |
Frage zum Disconnect mit Indy und einer TCP/IP Verbindung
Vorweg, ich habe im Forum gesucht, aber nicht die passenden Antworten gefunden.
Es geht hier um eine Verbindung, die ein TidTCPClient mit einer TidTCPServer-Komponente auf einem anderen PC im Netzwerk herstellt. Mir ist immer noch nicht ganz klar, ob es besser ist, 1. dass der Client eine mit dem Server hergestellte Verbindung wieder trennt, wenn der seine Informationen erhalten hat oder 2. dass der Server im OnExecute-Event auf jeden Fall die Verbindung trennt, wenn er die erwünschten Daten übermittelt hat? Oder sollten sogar beide (Client und Server) ein Disconnect ausführen? Oder wäre das problematisch? Kann es ein Nachteil sein, wenn die Verbindung "offen gehalten wird"? Bislang habe ich es immer so gemacht, dass die Verbindung immer wieder getrennt wird, wenn eine Abfrage beim Server stattgefunden hat und eben wieder neu aufgebaut wird, wenn das Clientprogramm weitere Abfragen starten muss. Im Prinzip funktioniert hier zwar alles mit meinen Verbindungen, ich bin mir aber nicht sicher, ob bei hoher Auslastung (halt einige Dutzend Clients, die Verbindung mit dem Server herstellen), die eine oder andere Vorgehensweise zu Problemen führen könnte. Falls neben einer Antwort gar ein Verweis auf guter Literatur zur Indy Client-Server-Programmierung möglich wäre, wäre ich dankbar. |
AW: Frage zum Disconnect mit Indy und einer TCP/IP Verbindung
Wenn man jetzt von klassischen Sockets ausgeht, dann sollten beide Seiten ihre Verbindung sauber schließen. Die Best-Praktice für Indy bzw. WinSock kenne ich nicht, die WinSocks sind ein bisschen merkwürdig.
Eine gehaltene Verbindung hat den Vorteil, das bei einer neuen Anfrage keine neue Verbindung aufgebaut werden muss. Durch den Handshake dauert das mindestens die doppelte Netzwerklatenz. Andererseits kosten offene Verbindungen eben auch (Verwaltung im Betriebssystem und der Anwendung) und es ergeben sich andere Probleme (Heartbeat zum offen halten? Wie lange offen halten?). |
AW: Frage zum Disconnect mit Indy und einer TCP/IP Verbindung
Du solltest die Verbindung offen halten. Der Overhead für das Betriebssystem ist nicht nennbar. Vermutlich sogar größer wenn du immer wieder eine neue öffnest. Es ist auch nicht zwingend notwendig einen Heartbeat mitzuschicken. Im Zweifel kann es passieren, dass du erst bei der Verwendung der Verbindung mitbekommst, dass die Verbindung nicht mehr steht. Hier musst du wissen, ob das ein Problem für dich ist.
Es ist auch kein Problem eine Verbindung länger offen zu halten. Einige interne Serversysteme halten monatelange Verbindungen (z.B. zwei MySQL Server). Na und? Dafür gewinnst du beim Schicken von Anfragen deutlich an Zeit. Ich weiß nicht, ob es überhaupt funktioniert wenn beide Clients die Verbindung schließen. Einer wird vermutlich schneller sein und der andere kann eine geschlossene Verbindung nicht erneut schließen. Leg es protokollbedingt fest, wer die Verbindung zu schließen hat. Wenn dein Server offene Verbindungen unterstützt, dann lass den Client entscheiden, wann er disconnected. Wenn dein Protokoll vorsieht, dass nach einer Anfrage die Verbindung geschlossen wird, dann entscheide dich von wem, dokumentiere es und setze es so um. Wichtig ist aber, dass entsprechend darauf eingegangen wird, was beispielsweise passiert wenn das Protokoll festlegt, dass die Verbindung geschlossen werden soll, dies jedoch nicht passiert. Eine weitere Anfrage über TCP zu senden wäre dann nicht gemäß der Spezifikation. |
AW: Frage zum Disconnect mit Indy und einer TCP/IP Verbindung
OK, erst mal Danke Euch beiden für die Antworten.
Offen halten klingt einerseits sympathisch, wegen der Beschleunigung. Wie ist es aber, wenn ein Client abstürzt und die Verbindung nicht mehr schließen kann und beim erneuten Programmstart dann wieder versucht eine Verbindung herzustellen? Kann die zuvor noch offen gebliebene Verbindung ein Hindernis darstellen? Wenn ja, wäre es eigentlich ein Argument, die Verbindung immer wieder zu schließen. Bisher habe ich immer beide Seiten disconnecten lassen. Im Programmablauf war das bislang kein sichtbares Problem. Aber ich bin mir eben unsicher. |
AW: Frage zum Disconnect mit Indy und einer TCP/IP Verbindung
Sofern dein Server es nicht explizit verbietet, dass die gleiche IP zwei mal verbunden ist, ist das kein Problem mit dem abgestürzten Client.
Was das Schließen angeht: ich denke das hängt auch von der Implementierung der Sockets ab. Insofern will ich mich diesbezüglich nicht zu weit aus dem Fenster lehnen, wie es bei dir ist. Ich würde nur den Client schließen lassen und die Verbindung serverseitig beliebig lang offenhalten. Der Client bestimmt, wann er fertig ist. Wie bei HTTP. |
AW: Frage zum Disconnect mit Indy und einer TCP/IP Verbindung
Ich nutze hier nur die INDY-Komponenten, spezielle Implementierungen in Bezug auf Sockets habe ich nicht vorgenommen.
Ich bin gerade dabei eine Server/Client Anwendung auf reines TCP/IP umzustellen. Zuvor hatte ich da noch eine wilde Mischung aus Mailslot-Technik (gruselig) und TCP-IP gehabt. Nur TCP/IP zu verwenden ist da deutlich einfacher. In einem Test gerade hier im Netz mit ca. 10 Rechnern (Verbindung teils über festes Netzwerk, teils WLan), teils Desktop, teils Notebook stellten sich folgende Probleme dar: Die Notebooks gingen relativ schnell "schlafen" und bekamen daher einige Meldungen vom Server nicht mehr mit. Hier stellt sich die Frage, wie mit dieser Situation umgehen: Die Notebooks, wenn man feststellt, dass die in den Tiefschlaf gehen, automatisch vom Server trennen? Oder, wenn wieder wach, die Datendatei aktualisieren / automatisch neu laden? Wie geht Ihr mit solchen Situationen um, damit die Konsistenz des Datenbestandes auf allen Rechner erhalten bleibt? |
AW: Frage zum Disconnect mit Indy und einer TCP/IP Verbindung
Das ist so allgemein schwer zu sagen, da ich deinen genauen Anwendungszweck nicht kenne.
Ich kann dir mal ein Beispiel geben, wie MySQL das macht. MySQL unterstützt einen Master-Slave-Modus, bei denen die Slaves ihren Datenbestand synchron zum Master halten. MySQL führt dabei eine Nummer mit, die mit jeder Änderung am Datenbestand erhöht wird. Die Slaves sind mit dem Master verbunden und führen Änderungen sequentiell ein. Startest du einen Slave neu, so beginnt er, dieses s.g. "Backlog" von seinem letzten Datenstand aufzuholen. Das klappt soweit meistens ganz gut. (Ich will nicht sagen dass das problemlos klappt, aber das Problem ist meist eher MySQL als dieses System) Es gibt einige Situationen, in denen man daran per Hand rumwerkeln muss. Beispielsweise führt der Server sein Backlog (also die Liste der Änderungen am Datenbestand) nicht unendlich lang. Ist ein Slave langer offline als das Backlog alt ist, so kann er den Bestand nicht mehr automatisch abgleichen. In dem Fall muss man vorgehen, wie man es auch beim Hinzufügen eines neuen Slaves tut. Dazu stellt man sicher, dass der Master seine Daten nicht mehr ändert (er speichert Änderungen solange im RAM) und macht ein Backup. Das Backup wird auf neue Slaves eingespielt. Der Master darf dann weiterarbeiten. Wichtig ist, das man vor dem reaktivieren des Masters aufschreibt, welche Revisionsnummer (also die Position im Backlog bzw. die Nummer die zur Synchronisation dient) das Backup hat. Nach dem Einspielen des Backups auf den Clients gibt man ihnen diese Nummer mit und sie sind wieder automatisch in der Lage synchron zum Master zu bleiben. Im Prinzip also eine Mischung aus beiden deiner Vorschläge. Das komplette Neuladen der Datenbestände muss man in MySQL leider manuell machen, das ließe sich aber bestimmt automatisieren in deinem Programm. Hilft dir das eventuell weiter als Ansatz? |
AW: Frage zum Disconnect mit Indy und einer TCP/IP Verbindung
Zitat:
Was mich an der Stelle auch mal interessieren würde: Bekommt man es eigentlich vorher mit (Message? Frage an die API-Spezies), dass Windows beabsichtigt den Rechner in den Ruhezustand zu versetzen? Dann könnte man clientseitig reagieren. |
AW: Frage zum Disconnect mit Indy und einer TCP/IP Verbindung
Ja die Message gibt es.
Eine schnelle Suche ergab: WM_ENDSESSION message ![]() In den Kommentare steht aber, dass man evtl. nur sehr wenig Zeit zur Verfügung hat bis der eigene Prozess abgewürgt wird. Ich würde da eher einen Ticken früher sichern, egal ob sich der Benutzer des Rechners es anders überlegt und doch nicht herunterfährt. WM_QUERYENDSESSION message ![]() Notfalls kann man den Shutdown verhindern indem der Rückgabewert auf False gesetzt wird. Findet sich auch schon im Forum: ![]() |
AW: Frage zum Disconnect mit Indy und einer TCP/IP Verbindung
Zitat:
Zitat:
Zitat:
Zitat:
Da die Datenbank i.d.R. maximal nur einige MB einnimmt, wäre auch ein stiller Reload machbar, wenn der Client merkt, er hat das eine oder andere verpasst. |
AW: Frage zum Disconnect mit Indy und einer TCP/IP Verbindung
[QUOTE=Photoner;1305223]Ja die Message gibt es.
Eine schnelle Suche ergab: WM_ENDSESSION message ![]() Ich glaube, es geht hier nicht das Herunterfahren. Die Notebooks schalten die Bildschirm ab und sind in einer Art Energiesparmodus. Ein Tastendruck und sie sind direkt wieder da. Allerdings wird hier ein Anmeldebildschirm angezeigt (wo ich aber kein Passwort erneut eingeben muss, da ich das so eingestellt habe). Also wird es eher um eine Abmeldenachricht gehen. Oder gibt es auch eine spezielle, ich gehen jetzt in den Energiespar-Modus Nachricht? Die Clients empfangen jedenfalls keine Nachrichten vom Server, wenn sie in diesem Energiesparmodus sind (hier im Beispiel Windows 8.1 auf dem Surface Pro 3). |
AW: Frage zum Disconnect mit Indy und einer TCP/IP Verbindung
Zitat:
Zitat:
![]() |
AW: Frage zum Disconnect mit Indy und einer TCP/IP Verbindung
Oh weh, 6 Jahre her und schon vergessen...
Bei dieser Diskussion kam eine dunkle Erinnerung hoch und siehe da, hatte vor längerer Zeit diese Problematik in einer anderen Client/Server Anwendung schon mal eingebaut, also für alle, die das evtl. mal brauchen könnten, hier, wie es geht:
Delphi-Quellcode:
procedure TF_Main.WMPowerBroadcast(var MyMessage: TMessage);
begin if MyMessage.Msg = WM_POWERBROADCAST then begin // windows powermanagement message if (MyMessage.WParam = PBT_APMSUSPEND) or (MyMessage.WParam = PBT_APMSTANDBY) or (MyMessage.WParam = PBT_APMQUERYSUSPEND) or (MyMessage.WParam = PBT_APMQUERYSTANDBY) then begin // Hier hin, was getan werden muss, bevor Windows in den Standby darf, // z.B. Netzwerk- oder Datenbankverbindungen trennen, Timer abstellen, etc. // Seit Vista hat man hier nur noch max. 2 Sekunden Zeit was zu erledigen. if NetFileMode then begin mnu_CloseMainFileClick (self); end; MyMessage.Result := 1; // Standby/Ruhezustand erlauben // MyMessage.Result := BROADCAST_QUERY_DENY; // Standby/Ruhezustand verweigern end else if (MyMessage.WParam = PBT_APMRESUMECRITICAL) or (MyMessage.WParam = PBT_APMRESUMESUSPEND) or (MyMessage.WParam = PBT_APMRESUMESTANDBY) then begin // Windows kommt aus dem Standby/Ruhezustand wieder. // Hier z.B. Verbindungen wiederherstellen. hs_delay (2000, True); if LastNetFile <> '' then begin if EstablishServerConnection = 'OK' then begin GetFileFromServer (AsStr (['UserId=' + MyNetUserID, 'cmd=GetThisFile', 'Password=' + LastPW, 'FileName=' + LastNetFile])); end; LastNetFile := ''; end; end; end; inherited; end; |
AW: Frage zum Disconnect mit Indy und einer TCP/IP Verbindung
[QUOTE=BUG;1305239]
Zitat:
|
AW: Frage zum Disconnect mit Indy und einer TCP/IP Verbindung
Hallo,
vielen Dank! Das ist genau das was ich gesucht habe! :thumb: |
AW: Frage zum Disconnect mit Indy und einer TCP/IP Verbindung
Zitat:
|
AW: Frage zum Disconnect mit Indy und einer TCP/IP Verbindung
Zitat:
![]() Wenn es denn geht. |
AW: Frage zum Disconnect mit Indy und einer TCP/IP Verbindung
Wobei ich feststellen muss, dass man sich jetzt wohl für die Broadcast-Nachricht explizit registrieren muss, um diese zu erhalten (war früher definitiv nicht so).
Habe hier weitere Informationen dazu gefunden: ![]() Allerdings meckert der Compiler hier: FHPOWERNOTIFY := RegisterPowerSettingNotification(Handle, @GUID_MONITOR_POWER_ON, DEVICE_NOTIFY_WINDOW_HANDLE); und sagt TGUID und Pointer seien Inkompatible Typen Die Variable ist als const GUID_MONITOR_POWER_ON: TGUID = '{02731015-4510-4526-99e6-e5a17ebd1aea}'; definiert. Wie geht's richtig? |
AW: Frage zum Disconnect mit Indy und einer TCP/IP Verbindung
Wobei es mehrere GUIDS gibt. Welche mag wohl die richtige für den Energiesparmodus sein:
Delphi-Quellcode:
GUID_POWERSCHEME_PERSONALITY: TGUID = '{245d8541-3943-4422-b025-13A784F679B7}';
GUID_MIN_POWER_SAVINGS: TGUID = '{8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c}'; GUID_MAX_POWER_SAVINGS: TGUID = '{a1841308-3541-4fab-bc81-f71556f20b4a}'; GUID_TYPICAL_POWER_SAVINGS: TGUID = '{381b4222-f694-41f0-9685-ff5bb260df2e}'; GUID_ACDC_POWER_SOURCE: TGUID = '{5d3e9a59-e9D5-4b00-a6bd-ff34ff516548}'; GUID_BATTERY_PERCENTAGE_REMAINING: TGUID = '{a7ad8041-b45a-4cae-87a3-eecbb468a9e1}'; GUID_IDLE_BACKGROUND_TASK: TGUID = '{515c31d8-f734-163d-a0fd-11a08c91e8f1}'; GUID_SYSTEM_AWAYMODE: TGUID = '{98a7f580-01f7-48aa-9c0f-44352c29e5C0}'; GUID_MONITOR_POWER_ON: TGUID = '{02731015-4510-4526-99e6-e5a17ebd1aea}'; |
AW: Frage zum Disconnect mit Indy und einer TCP/IP Verbindung
Delphi-Quellcode:
Lass das mit dem @. Parameter ist vom Typ TGUID.
function RegisterPowerSettingNotification(const hRecipient: THandle;
const PowerSettingGuid: TGUID; const Flags: DWORD): HPOWERNOTIFY; stdcall; PBT_APMSUSPEND event ![]() |
AW: Frage zum Disconnect mit Indy und einer TCP/IP Verbindung
Das hatte ich natürlich auch schon gemacht und dennoch eine Fehlermeldung erhalten. Gerade habe ich aber gesehen, dass diese Fehlermeldung sich dann auf den Rückgabewert bezog: "Inkompatible Typen NativeUInt und Pointer".
FHPOWERNOTIFY: THandle; Das muss also ein Pointer statt ein Thandle sein. |
AW: Frage zum Disconnect mit Indy und einer TCP/IP Verbindung
Zitat:
![]() Obwohl es mit dem Monitor-Power_on durchaus geht, scheint mir evtl. hier noch "GUID_SYSTEM_AWAYMODE" am passendsten zu sein. Muss ich mal testen. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 09:28 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz