Delphi-PRAXiS
Seite 1 von 8  1 23     Letzte »    

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Netzwerke (https://www.delphipraxis.net/14-netzwerke/)
-   -   Delphi schnelle Server Client Verbindung ohne Verluste (https://www.delphipraxis.net/216953-schnelle-server-client-verbindung-ohne-verluste.html)

AJ_Oldendorf 28. Mär 2025 07:46

schnelle Server Client Verbindung ohne Verluste
 
Guten Morgen zusammen,
basierend auf diesem Thread, habe ich eine Indy Server und Client Anwendung:
https://www.delphipraxis.net/216803-...nge-tcpip.html

Dabei ist mir allerdings folgendes aufgefallen:

1) erstmal die Aufgabenstellung:
Ich muss vom Server viele Daten zum Client senden und der Client auch genau in der Reihenfolge abarbeiten/verarbeiten.
"Viele Daten" können zwischen 20 und 80 Datensätze (alle unterschiedlich!) pro Sekunde sein. Es dürfen sich keine Datensätze überholen bzw ausfallen. Die Telegramme können zwischen 13 Byte und max 61000 Byte lang sein!
Der Ausfall wird über Connect/Disconnect erkannt.
Dafür wollte ich Indy TCPIP nehmen. Verbindungsaufbau und -abbau klappt soweit, kein Problem.


2) Beobachtungen im Client:
Datensätze werden im Client im einem Thread eingelesen und zwar so:

Delphi-Quellcode:
IdTCPClient1.IOHandler.CheckForDataOnSource(10);

if not IdTCPClient1.IOHandler.InputBufferIsEmpty then
begin
  InData := IdTCPClient1.IOHandler.ReadLn('#~#*' + EOL, 100, -1, IndyTextEncoding_UTF8);

  if InData <> '' then
  begin
    //mach irgendwas damit
  end;
end;
Dabei ist mir aufgefallen, dass der Client die Datensätze nicht in der Geschwindigkeit abholen kann, wie der Server sie mit WriteLn schickt. Auch mit dem Timeout (100) habe ich schon rumgespielt (erhöht, verringert), keine Besserung. Der Client hängt merklich hinterher. Wenn ich im Server das Senden unterdrücke, kann man beim Client richtig zugucken, wie die ReadLn Befehle weiter arbeiten und noch Datensätze abgeholt werden obwohl der Server ja eigentlich nicht mehr schickt (die sind also gepuffert). Das mit dem Puffer ist ja erstmal nicht schlecht, aber der Client kann den Server nie wieder "einholen" wenn der Server aktiv weiterschicken würde. Im Gegenteil, das "hinterherhängen" wird immer schlimmer.
Zur Info, der Server schickt mit WriteLn und Terminator.

3) Frage:
Ist TCPIP dafür überhaupt der richtige Ansatz für meine Aufgabenstellung? Gibt es eine andere Möglichkeit, Daten von einem Server an einem Client in dieser Geschwindigkeit zu schicken und der Client kann diese auch entsprechend verarbeiten? Also wenn der Client mal "bisschen" hinterher hängt, ist ja nicht schlimm aber es darf nicht immer mehr werden. Mit UDP habe ich mal versucht, dass ist natürlich super schnell aber da überholen sich Telegramme und es fallen auch welche aus (ich weiß warum, deswegen fällt UDP raus).

Wie würdet ihr das versuchen zu lösen?

Sinspin 28. Mär 2025 08:01

AW: schnelle Server Client Verbindung ohne Verluste
 
Die Art der Übertragung ist mit Sicherheit nicht das Problem.
Deine Flaschenhälse sind an anderen Stellen.
Zum einen würde ich mir überlegen die Datenpakete zu indexieren damit du rausbekomst ob dazwischen was fehlt.
Weiter musst Du die Verarbeitung vom Empfang trennen. Die Datenpakete müssen also beim Empfang einfach weggespeichert werden und andere Threads kümmern sich ums auswerten.

Wenn das Projekt kommerziell ist, legt dir andere Komponenten für die Übertragung zu. Wir verenden seit vielen Jahren NSoftware. Du musst dich um nichts kümmern, es funktioniert einfach.

Was sind denn eigentlich viele Daten? Bytes pro Sekunde? MB? GB?

AJ_Oldendorf 28. Mär 2025 08:32

AW: schnelle Server Client Verbindung ohne Verluste
 
Zitat:

Was sind denn eigentlich viele Daten? Bytes pro Sekunde? MB? GB?
Die Telegramme können zwischen 13 Byte und max 61000 Byte lang sein.

Ja, die Software ist kommerziell.
NSoftware kenne ich nicht, was ist da "anders/besser"?
Welches Produkt von NSoftware meinst du denn genau?

Die Geschwindigkeitsmessung habe ich auch direkt am WriteLn und ReadLn gemacht. Die Verarbeitung habe ich noch gar nicht geprüft. Das heißt, die Zeit geht ja da verloren bzw man sieht, dass das ReadLn hinterher hängt. Denke nicht, dass es mit der Software drum herum zusammen hängt.

Sinspin 28. Mär 2025 09:23

AW: schnelle Server Client Verbindung ohne Verluste
 
Ich habe mit Indy das letzte mal vor mehr als 10 Jahren gearbeitet. Keine Ahnung ob die jetzt Event basierten Datenempfang haben. (NSoftware macht das sehr schön)
Ich hatte mir das selber geschrieben. Also einen Thread der nichts anderes gemacht hat als immer wieder zu fragen ob was im Eingangspuffer ist, das in einen Zwischenpuffer geschrieben und den immer wieder untersucht bis darin ein vollständiger Datenblock gefunden wurde.
Der Datenblock wurde dann extrahiert und ein Flag gesetzt an dem ein anderer Thread erkannt hat das es was zu tuen gibt.
Kam da mal Müll dazwischen, also ein Datenblock kam nicht vollständig durch, musste der später nochmal angefragt werden.
Wobei ich das mit IP Works jetzt nicht wirklich anders mache. Es läuft nur einfach schön flüssig.

Aber eigentlich sollte es auch mit ReadLn gehen. Es sei denn beim Sender geht das "Ln" nicht raus. Dann wartest du bis zum Timeout für das aktuelle Paket und die dahinter türmen sich bis der interne Puffer voll ist.

Zeig mal deine komplette Config für das Init vom Client. Nicht das nur in der Config was nicht zu dir passt.


NSoftware : IP Works / IP Works SSL.

Papaschlumpf73 28. Mär 2025 09:30

AW: schnelle Server Client Verbindung ohne Verluste
 
Von IPWorks gibts auch eine kostenlos nutzbare (leider auch etwas eingeschränkte) Delphi-Edition über GetIt.

AJ_Oldendorf 28. Mär 2025 09:50

AW: schnelle Server Client Verbindung ohne Verluste
 
NSoftware : IP Works / IP Works SSL muss ich mir mal angucken, auch was es da über GetIt gibt.

Aktuell sieht es so aus:

Server:

Delphi-Quellcode:
IdTCPServer.DefaultPort := PipePort;
IdTCPServer.OnConnect   := IdTCPServerConnected;
IdTCPServer.OnDisconnect := IdTCPServerDisconnected;
IdTCPServer.OnException := IdTCPServerException;
IdTCPServer.OnExecute   := IdTCPServerExecute;
IdTCPServer.Active      := True;

procedure IdTCPServerExecute(AContext: TIdContext);
begin
  if IdTCPServer.Active then
  begin
    AContext.Connection.IOHandler.CheckForDataOnSource(10);

    if not AContext.Connection.IOHandler.InputBufferIsEmpty then
    begin
      InData := AContext.Connection.IOHandler.ReadLn('#~#*' + EOL, 100, -1, IndyTextEncoding_UTF8);
      if InData <> '' then
      begin
        //mach irgendwas
      end;
  end;
end;
Im IdTCPServerConnected, IdTCPServerDisconnected und IdTCPServerException sind nur Protokollierungen. Die sind aber auch nicht zu sehen, kommen also nicht (außer natürlich das 1x Connect, da ein Client sich verbindet).

Client:

Delphi-Quellcode:
IdTCPClient1.OnConnected   := IdTCPClientConnected;
IdTCPClient1.OnDisconnected := IdTCPClientDisconnected;
IdTCPClient1.OnStatus      := IdTCPClientStatus;
IdTCPClient1.Host := aServerIP;
IdTCPClient1.Port := aPort;

procedure TMyThread.Execute;
begin
  while not Terminated do
  begin
    IdTCPClient1.IOHandler.CheckForDataOnSource(10);

    if not IdTCPClient1.IOHandler.InputBufferIsEmpty then
    begin
      InData := IdTCPClient1.IOHandler.ReadLn('#~#*' + EOL, 100, -1, IndyTextEncoding_UTF8);

      if InData <> '' then
      begin
        //mach irgendwas
      end;
  end;
end;
Im IdTCPClientConnected, IdTCPClientDisconnected und IdTCPClientStatus sind nur Protokollierungen. Die sind aber auch nicht zu sehen, kommen also nicht (außer natürlich das 1x Connect, da der Client sich verbindet).

Natürlich ist noch mehr Quelltext drum herum aber das ist die Implementierung von Server und Client.
Wie gesagt, der Server schickt im Durchschnitt 60 Datensätze (unterschiedlicher Inhalt) pro Sekunde mit einer Länge von 13 Byte bis max 61000 Byte

Papaschlumpf73 28. Mär 2025 10:04

AW: schnelle Server Client Verbindung ohne Verluste
 
Stefan meinte wohl das hier im .Execute

Delphi-Quellcode:
      if InData <> '' then
      begin
        //mach irgendwas
      end;
Hier sollten die Daten nur weggespeichert und ggf. durch einen anderen Thread verarbeitet werden. Sonst kann hier ein Flaschenhals entstehen.

fisipjm 28. Mär 2025 10:13

AW: schnelle Server Client Verbindung ohne Verluste
 
Darf ich dazu mal eine "blöde" Frage stellen?
Was für Daten möchtest du denn Übertragen? Was bedeutet denn Datensätze?
Ich würde es mir an deiner Stelle nicht so kompliziert machen. Um Daten von einem Server zu einem Client zu Übertragen schlägt man sich normalerweise nicht mehr mit TCP und dem ganzen geraffel herum.

Best-Practice wäre aus meiner Sicht folgendes:
1.) Auf der Server Seite setzt du dir einen kleinen Webserver auf. Minimale Lösung z.B. Horse. (Bei der Gelegenheit kann man sich auch gleich mal mit Boss auseinandersetzen, vom Grundprinzip sowas wie der Packagemanager nvm nur für Delphi). Wenn du dann auch noch jwt als middleware nutzt, hast du auch gleich noch etwas das sich brauchbar um die Verschlüsslung deiner Kommunikation kümmert.
2.) Deine Datensätze Packst du in Klassen. Wenn du mehrere Datensätze auf einmal Schicken willst packste dir die Klassen in ein Tarray<MyClass> und lässt es danach mit TJSON.ObjectToJSONStr serialisieren. (oder du nimmst gleich irgend ein ORM, oder, oder, oder)


Vorteile:
Aus meiner Sicht kommst du damit locker an die von dir angesprochenen ca. 3,5 MB pro Sekunde (61000Byte x 60(Pakete/s) / 1024 / 1024) hin.
Du brauchst dich nicht mehr um die Reihenfolge kümmern.
Du brauchst dich nicht mehr um das ganzen TCP/IP Connection Zeug kümmern.

Nachteil:
Overhead des HTTP layers, aber wie gesagt, deine Datenrate solltest du damit dicke schaffen.

Ansonsten kannst du die auch mal Websocket zu diesem Thema anschauen. Das ist aber eine ganze Ecke komplizierter.

vG
PJM

Bernhard Geyer 28. Mär 2025 11:08

AW: schnelle Server Client Verbindung ohne Verluste
 
Zitat:

Zitat von Sinspin (Beitrag 1547564)
Zum einen würde ich mir überlegen die Datenpakete zu indexieren damit du rausbekomst ob dazwischen was fehlt.

TCP hat doch selbst eine Prüfung mit Sequenznummer.
Wenn man sowas "selbst in die Hand nimmt", dann würde man auf UDP setzen.
Da gibt es das nicht und muss von der eigenen Anwendung geprüft werden.
Vorteil wäre das man damit das dann auf Geschwindigkeit optimieren kann, wo TCP systembedingt langsamer sein muss.

AJ_Oldendorf 28. Mär 2025 11:10

AW: schnelle Server Client Verbindung ohne Verluste
 
Zitat:

Stefan meinte wohl das hier im .Execute
Also ich habe jetzt jeweils nach dem Senden und Empfang keiner weiteren Aktivitäten mehr, der Client hängt trotzdem hinterher (wesentlich!).

Ein Versuch wäre noch, beides mal wirklich in kleine separate Threads auszulagern, jetzt ist noch ein wenig Overhead drum herum was vielleicht ein Problem sein könnte. Ich werde dazu berichten.

Zitat:

Darf ich dazu mal eine "blöde" Frage stellen?
Also im Endeffekt sind das codierte Strings die dann irgendwelche Commands enthalten und irgendwelche Werte / Signale.

Zitat:

Ich würde es mir an deiner Stelle nicht so kompliziert machen
Naja, das TCPIP Connect/Disconnect geht ja prinzipiell. Dein Vorschlag mir Server und irgendeiner Middleware und JSON etc hört sich aus meiner Sicht erstmal kompliziert an, da davon bei uns aktuell 0 existiert und man sich damit von Grund auf neu beschäftigen müsste. Das andere ist ja da und muss nur implementiert werden. Nicht falsch verstehen, ich bin gerne offen für eine andere Lösung aber wenn dazu erst noch dies und das eingerichtet/gehostet werden muss, ist das nicht praktikabel in unserem Fall. Es soll am Ende nur von einer Windows Anwendung zu einer anderen Windows Anwendung Daten übertragen werden. Diese läuft jeweils auf einem anderen Rechner. Server schickt dem Client was, Client kann dem Server antworten. Das ist das Grundprinzip

Zitat:

Vorteil wäre das man damit das dann auf Geschwindigkeit optimieren kann, wo TCP systembedingt langsamer sein muss.
Genau das habe ich auch schon versucht mit UDP und habe eine Sequenz eingebaut. Wenn man diese mit einbaut, ist es im Prinzip wieder so schnell/langsam wie TCP, da der Client jedes Telegram beantworten muss (damit der Server feststellt, dass es angekommen ist) und der Server muss es wiederholen, falls es vom Client nicht quittiert wurde. Und ohne Sequenz kann man UDP vergessen, da Telegramme verloren gehen können oder sich überholen. Fällt dahe raus


Alle Zeitangaben in WEZ +1. Es ist jetzt 08:26 Uhr.
Seite 1 von 8  1 23     Letzte »    

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