AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Netzwerke Delphi Indy-Test optimieren
Thema durchsuchen
Ansicht
Themen-Optionen

Indy-Test optimieren

Ein Thema von stahli · begonnen am 25. Apr 2014 · letzter Beitrag vom 28. Apr 2014
Antwort Antwort
Seite 1 von 2  1 2      
Benutzerbild von stahli
stahli

Registriert seit: 26. Nov 2003
Ort: Halle/Saale
4.337 Beiträge
 
Delphi 11 Alexandria
 
#1

Indy-Test optimieren

  Alt 25. Apr 2014, 00:38
Hallo zusammen,

nachfolgendes ist nur etwas für Leute mit starken Nerven - bzw. mit Kenntnissen von Indy und ausreichend Tagesfreizeit

Also: Ich habe ein kleines Testprojekt (XE3)...


Server:
Ein Server verwaltet ein Integer-Array und stellt die Werte als Linien in einem Bitmap dar, das über einen Timer in das Formular kopiert wird.
Die Werte werden durch das Array geschoben, um einen optischen Effekt zu haben.
Klick in das Formular dreht die Darstellung jeweils um 90 Grad.

Das Array und der Turn(Dreh)-Wert sind einfach mal global verwaltet und reine Integer, damit es keine Syncro-Probleme gibt.


Clients:
Die Clients haben die gleiche Datenstruktur und Darstellung.
Aber über Indy werden nacheinander zyklisch alle Zahlenwerte und der Turn-Wert abgerufen.
Dieser Abruf läuft in einem Thread, damit das Formular "bedienbar" bleibt.
Ein Formular-Click sendet in dem Fall einen Dreh-Auftrag an den Server.


Die Werte-Übertragung läuft über Streams (mit Umweg über eine StringList), damit optional auch Umlaute übertragen werden könnten.


Im Grunde funktioniert das soweit - ABER!
Das ist natürlich recht langsam und die Clients bleiben gelegentlich auch hängen.


Ich weiß, dass ich in dem Testprojekt VIELES falsch mache. Aber zumindest das globale Array bitte ich hier mal großzügig zu übersehen.
Mir geht es hier darum, den Datenaustausch zwischen Server und Client zu optimieren und stabil zu gestalten.

Real soll der Server eine Menge von Daten verwalten, von denen sich die Clients nach Bedarf einige abrufen bzw. auch Aufträge den Server senden.
Über einen abzurufenden Zeitstempel können die Clients prüfen, ob der Server über neue Daten verfügt. Wenn nicht, werden gepufferte Daten genutzt.
Hier im Beispiel will ich diese Prüfungen vernachlässigen.

Wenn es gelingt, die Grafik in den Clients flüssig aktualisieren zu lassen wäre ich schon sehr zufrieden.

Bei Indy würde ich eigentlich gern bleiben, da man so ja auch noch andere Möglichkeiten wie eMail usw. hätte.
Es wäre aber auch ein genereller Wechsel möglich, wenn das etwas bringen würde.


Drei Hinweise noch:
- natürlich will ich nicht das Bitmap vom Server an die Clients schicken
- und die Clients können nicht wissen, welche Werte sich auf dem Server geändert haben.
- Die realen Daten können auch Sonderzeichen und Umlaute enthalten


Wäre super, wenn sich das jemand mal anschauen könnte...

Anbei
- Video
- XE3-Projekt
- Exen (in den Ini´s müsstet Ihr am besten Eure IP eintragen)

(Sorry, ist halt ziemliches Stückelwerk.)
Angehängte Dateien
Dateityp: zip NetCalc-Video.zip (3,19 MB, 21x aufgerufen)
Dateityp: zip NetCalc-XE3.zip (217,5 KB, 17x aufgerufen)
Dateityp: zip NetCalc-Exen.zip (1,80 MB, 12x aufgerufen)
Stahli
http://www.StahliSoft.de
---
"Jetzt muss ich seh´n, dass ich kein Denkfehler mach...!?" Dittsche (2004)
  Mit Zitat antworten Zitat
Benutzerbild von Sir Rufo
Sir Rufo

Registriert seit: 5. Jan 2005
Ort: Stadthagen
9.454 Beiträge
 
Delphi 10 Seattle Enterprise
 
#2

AW: Indy-Test optimieren

  Alt 25. Apr 2014, 01:01
Was hast du denn für ein Problem mit den Strings und Umlauten und Streams?

Dafür gibt es Hilfsklassen (z.B. Delphi-Referenz durchsuchenTStreamWriter/Delphi-Referenz durchsuchenTStreamReader) und schwupps sind die Daten im Stream und wieder aus dem Stream.
Kaum macht man's richtig - schon funktioniert's
Zertifikat: Sir Rufo (Fingerprint: ‎ea 0a 4c 14 0d b6 3a a4 c1 c5 b9 dc 90 9d f0 e9 de 13 da 60)
  Mit Zitat antworten Zitat
Benutzerbild von stahli
stahli

Registriert seit: 26. Nov 2003
Ort: Halle/Saale
4.337 Beiträge
 
Delphi 11 Alexandria
 
#3

AW: Indy-Test optimieren

  Alt 25. Apr 2014, 10:38
(ich muss das jetzt mal aus der Erinnerung zusammen fassen)

Socket.Writeln(' Text mit é ') führte immer zu einer Verstümmelung. Je nachdem welche Textart ich angegeben habe (UTF8 o.ä.) wurden auch Umlaute verstümmelt. Eine fehlerfreie Textübertragung mit Sonderzeichen und Umlauten habe ich nicht hin bekommen.

Daher der Weg über Streams.

TStreamReader und TStreamWriter waren mir nicht mehr geläufig.
Andererseits hatte ich auch überlegt, die Anweisung und Parameter ohnehin als StringList zu übertragen:
Zitat:
Anweisung
Param1
Param2
Param3
So hätte man dann leichteren Zugriff auf die einzelnen Parameter.

Meine wichtigere Frage wäre aber die Gestaltung des Datenaustausches gewesen. Das ist sicher noch sehr suboptimal, insbesondere wenn mehrere Clients Daten abrufen.

Wie machen das denn Onlinespiele?
Im Grunde könnte man ja die laufenden Linien als Spielfiguren ansehen und die Clients rufen ab, welche Linie (oder Figur) jetzt wo und wie gezeichnet werden muss.

Meine Lösung ist einfach viel zu langsam und ich weiß nicht, wie man das besser gestalten könnte.
Stahli
http://www.StahliSoft.de
---
"Jetzt muss ich seh´n, dass ich kein Denkfehler mach...!?" Dittsche (2004)

Geändert von stahli (25. Apr 2014 um 13:01 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von Union
Union

Registriert seit: 18. Mär 2004
Ort: Luxembourg
3.490 Beiträge
 
Delphi 7 Enterprise
 
#4

AW: Indy-Test optimieren

  Alt 25. Apr 2014, 11:26
Was ist denn nun genau langsam? Der Server, die Clients oder was? Ich habe mir jetzt nur den Server angeschaut. Da kann man schon Einiges optimieren. Aber das wäre ehe "Feintuning". Versuch doch mal herauszufinden, in welchen Routinen / Zeilen am meisten Zeit verbaten wird.
Als erstes würde ich aber auf das Ganze auf UDP umstellen, da Du sonst den ganzen Protokoll-Ballast mitschleppst. Es sein denn Du willst mal irgendwas tunneln oder es womöglich als http tarnen.
Ibi fas ubi proxima merces
sudo /Developer/Library/uninstall-devtools --mode=all
  Mit Zitat antworten Zitat
Benutzerbild von Sir Rufo
Sir Rufo

Registriert seit: 5. Jan 2005
Ort: Stadthagen
9.454 Beiträge
 
Delphi 10 Seattle Enterprise
 
#5

AW: Indy-Test optimieren

  Alt 25. Apr 2014, 12:28
Bei einem Online-Spiel können die Daten extrem reduziert werden.

Ein Objekt (Spieler, Rakete, Baum) ist vom Aussehen und Verhalten klar definiert und wird wenn nötig am Anfang des Spiels einmal übertragen (Farben, Polygone, Texturen, ...)

Bei Änderungen werden nur noch Position und Status übertragen und nicht das gesamte Objekt.

z.B. Rakete fliegt mit folgendem Bewegungsvektor [x,y,z] von Position [x,y,z]
und nur weil die Rakete weiterfliegt, werden keine neuen Daten übertragen, denn das Flugverhalten ist bekannt und kann ohne weitere Daten von jedem Client berechnet werden.
Kaum macht man's richtig - schon funktioniert's
Zertifikat: Sir Rufo (Fingerprint: ‎ea 0a 4c 14 0d b6 3a a4 c1 c5 b9 dc 90 9d f0 e9 de 13 da 60)
  Mit Zitat antworten Zitat
Benutzerbild von stahli
stahli

Registriert seit: 26. Nov 2003
Ort: Halle/Saale
4.337 Beiträge
 
Delphi 11 Alexandria
 
#6

AW: Indy-Test optimieren

  Alt 25. Apr 2014, 12:47
@Sir Rufo

Ja aber ich habe im Beispiel auch nur 300 Zahlenwerte.


@Union

Was genau so langsam ist habe ich noch nicht gecheckt. Ist im Zusammenspiel zwischen Server und Clients wohl auch nicht ganz so einfach.
Vielleicht ist das zeitliche Verhalten ja auch in Ordnung und gar nicht mehr gravierend zu verbessern. Dann wäre mein ursprüngliches Ziel auf dem Wege wohl nicht zu erreichen.
Es hätte natürlich auch sein können, dass mein Server oder die Clients grundsätzlich falsch aufgebaut sind.

UDP ist ja offenbar eine fehleranfälligere Übertragungsform. Fehler müssten dann also explizit geprüft und ausgebessert werden.
Würde das deutliche Geschwindigkeitsvorteile bringen?

Eigentlich muss die Datenübertragung zuverlässig im lokalen Netz und evtl. auch über Internet funktionieren. Genauere Anforderungen habe ich derzeit nicht.
Stahli
http://www.StahliSoft.de
---
"Jetzt muss ich seh´n, dass ich kein Denkfehler mach...!?" Dittsche (2004)
  Mit Zitat antworten Zitat
mjustin

Registriert seit: 14. Apr 2008
3.006 Beiträge
 
Delphi 2009 Professional
 
#7

AW: Indy-Test optimieren

  Alt 25. Apr 2014, 20:31
Nun, die erste Optimierungsmöglichkeit die auffällt ist:

anstatt für jeden einzelnen Integerwert eine Verbindung zu Server aufzubauen, einen Request zu senden, den Integerwert abzuholen (mit S := ReadText(IdTCPClient1, '?' + IntToStr(Index));) und dann die TCP Verbindung zu schliessen, nur einmal pro Zyklus die Verbindung aufbauen und einen kompletten Datenblock (300 Integerwerte) abrufen. Und die Verbindung nur nach einem Datenblock schliessen, oder nur bei Fehlern und beim Programmende.

Ein potentieller Störfaktor ist das "fForm.Caption := DateTimeToStr(Now);", das ist ein nicht-threadsicherer Zugriff auf ein Objekt der Oberfläche.
Michael Justin

Geändert von mjustin (25. Apr 2014 um 21:13 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von sx2008
sx2008

Registriert seit: 15. Feb 2008
Ort: Baden-Württemberg
2.332 Beiträge
 
Delphi 2007 Professional
 
#8

AW: Indy-Test optimieren

  Alt 25. Apr 2014, 22:18
anstatt für jeden einzelnen Integerwert eine Verbindung zu Server aufzubauen...
Das dürfte eine Verbesserung von 180-fach (!) bringen.
TCP-Verbindungsaufbau: 3 Pakete
TCP-Verbindungsaufbau: 2 Pakete
Das sind dann 300 * (5 + 1) = 1800 Pakete
Schickt man alles auf einen Rutsch sind das: 5 Pakete + ca. 5 Pakete für Nutzdaten = 10 Pakete
1800 / 10 = 180
Die ACK-Pakete habe ich nicht berücksichtigt, aber das dürfte wenig ändern
fork me on Github
  Mit Zitat antworten Zitat
Benutzerbild von stahli
stahli

Registriert seit: 26. Nov 2003
Ort: Halle/Saale
4.337 Beiträge
 
Delphi 11 Alexandria
 
#9

AW: Indy-Test optimieren

  Alt 25. Apr 2014, 23:00
Oh Mann, da hätte "man" ja auch mal selbst drauf kommen können.
Es ist ja nachvollziehbar, dass der Verbindungsaufbau immer etwas Zeit kostet.

Jetzt übertrage ich die 301 Werte einfach als String-Liste und lese sie en Block wieder aus.
Das funktioniert hier auf dem PC erst mal ohne sichtbare Verzögerung, auch bei mehreren Clients.

Delphi-Quellcode:
// Server:
  ..
  else if (cmd = '?ALL') then
  begin
    S := IntToStr(T);
    for Index := Low(A) to High(A) do
      S := S + #13#10 + IntToStr(A[Index]);
    SendText(AContext, S);
  end
  ..

// Client:
  ..
  procedure ReadText(FClient: TIdTCPClient; cmd: String; SL: TStringList);
  var
    MS: TMemoryStream;
    I: Int64;
  begin
    FClient.Connect;
    if FClient.Connected then
    begin
      MS := TMemoryStream.Create;
      try
        FClient.Socket.WriteLn(cmd);
        I := FClient.Socket.ReadInt64;
        FClient.Socket.ReadStream(MS, I, false);
        MS.Position := 0;
        SL.LoadFromStream(MS);
        // Result := Copy(SL.Text, 1, Length(SL.Text) - 2); // SL.Text; //
      finally
        MS.Free;
      end;
    end;
    FClient.Disconnect;
  end;
  ..
    ReadText(IdTCPClient1, '?ALL', SL);
    T := StrToInt(SL[0]);

    Index := 1;
    while Index < SL.Count do
    begin
      A[Index] := StrToInt(SL[Index]);
      Inc(Index);
    end;
  ..
Wenn ich später von 1Mio Datensätzen 300 abrufen will, dann werde ich einfach die 300 Id`s, RecNo o.ä. in einer Anfrageliste übergeben und die Ergebnisse dann vom Server aus anfügen und zurück schicken.
Insofern macht es schon Sinn, direkt mit Stringlists zu arbeiten.


Vielen Dank Euch allen für die Hilfe! (und für mjustin ein extra)
Stahli
http://www.StahliSoft.de
---
"Jetzt muss ich seh´n, dass ich kein Denkfehler mach...!?" Dittsche (2004)
  Mit Zitat antworten Zitat
Benutzerbild von Sir Rufo
Sir Rufo

Registriert seit: 5. Jan 2005
Ort: Stadthagen
9.454 Beiträge
 
Delphi 10 Seattle Enterprise
 
#10

AW: Indy-Test optimieren

  Alt 25. Apr 2014, 23:15
Solange man um die Besonderheiten der StringList weiß und die keine Stolperfallen darstellen, kann man die nehmen, wie jedes andere Konstrukt, was sich in einen Stream und wieder zurück wandeln lässt.
Delphi-Quellcode:
sl.Add('test' + sLineBreak + 'data' );
writeln( sl[0] ); // test#13#10data

sl.SaveToStream( sm );
sm.Position := 0;
sl.LoadFromStream( sm );

writeln( sl[0] ); // test
Kaum macht man's richtig - schon funktioniert's
Zertifikat: Sir Rufo (Fingerprint: ‎ea 0a 4c 14 0d b6 3a a4 c1 c5 b9 dc 90 9d f0 e9 de 13 da 60)
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 1 von 2  1 2      


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 05:40 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz