AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Netzwerke Delphi Schnellere Kommunikation mit einer Fritzbox
Thema durchsuchen
Ansicht
Themen-Optionen

Schnellere Kommunikation mit einer Fritzbox

Ein Thema von Dalai · begonnen am 11. Okt 2017 · letzter Beitrag vom 13. Okt 2017
Antwort Antwort
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.373 Beiträge
 
Delphi 12 Athens
 
#1

AW: Schnellere Kommunikation mit einer Fritzbox

  Alt 12. Okt 2017, 09:35
Diese Schleife Endet, wenn sie nichts empfing.
Also wenn die Übertragung beendet ist, wenn der Sender noch nichts liefern konnte (die angeforderten Daten noch zusammensucht) oder wenn er langsamer sendet, als den nächsten Lesedurchgang machst.

Erstmal könnte man sofort lesen und bei einem bekannten/erkannten "Ende" sofort aufhören
und ansonsten die Schleife nicht sofort bei "nichts gelesen" beenden, sondern DORT das "Sleep" integrieren, also nicht (ReadCount = 0) sondern (ReadCount = 0) and (LetzteZeitWoCountGrößer0 > xxxMilliekunden) .
Ein Therapeut entspricht 1024 Gigapeut.
  Mit Zitat antworten Zitat
mjustin

Registriert seit: 14. Apr 2008
3.010 Beiträge
 
Delphi 2009 Professional
 
#2

AW: Schnellere Kommunikation mit einer Fritzbox

  Alt 12. Okt 2017, 11:49
Was spricht gegen Indy oder Synapse für die Socket-Kommunikation zu verwenden? Damit würden einige Problemquellen wegfallen.
Michael Justin
  Mit Zitat antworten Zitat
Benutzerbild von Dalai
Dalai
Online

Registriert seit: 9. Apr 2006
1.684 Beiträge
 
Delphi 5 Professional
 
#3

AW: Schnellere Kommunikation mit einer Fritzbox

  Alt 12. Okt 2017, 16:29
Ich hab mal im OP den ursprünglichen Code von Garfield ergänzt, denn letztlich geht's um den und nicht um meine Modifikation zu Testzwecken.

Diese Schleife Endet, wenn sie nichts empfing.
Sofern du dich auf meine repeat -Schleife beziehst: Ja, richtig. Die Schleife endet aber auch, wenn der Socket geschlossen wurde. Vermutlich wird er das nicht, weil vorher setsockopt gerufen wird und dort ein keep-alive gesetzt wird.

Zitat:
Erstmal könnte man sofort lesen und bei einem bekannten/erkannten "Ende" sofort aufhören
Dazu müsste man die Content-Length aus dem HTTP Header auswerten, richtig? Oder wie sonst würde man ein Ende erkennen? Problem: der HTTP-Header selbst ist Bestandteil dessen, was die Methode ReceiveBuffer empfängt.

Zitat:
und ansonsten die Schleife nicht sofort bei "nichts gelesen" beenden, sondern DORT das "Sleep" integrieren, also nicht (ReadCount = 0) sondern (ReadCount = 0) and (LetzteZeitWoCountGrößer0 > xxxMilliekunden) .
Das verstehe ich (noch) nicht. Kannst du das etwas näher ausführen? Inwiefern umgeht man damit das Blockieren bei wiederholten Aufrufen der recv-Funktion (nachdem die Box fertig ist mit Senden)?

Grüße
Dalai
  Mit Zitat antworten Zitat
Namenloser

Registriert seit: 7. Jun 2006
Ort: Karlsruhe
3.724 Beiträge
 
FreePascal / Lazarus
 
#4

AW: Schnellere Kommunikation mit einer Fritzbox

  Alt 13. Okt 2017, 12:00
Zitat:
Erstmal könnte man sofort lesen und bei einem bekannten/erkannten "Ende" sofort aufhören
Dazu müsste man die Content-Length aus dem HTTP Header auswerten, richtig? Oder wie sonst würde man ein Ende erkennen? Problem: der HTTP-Header selbst ist Bestandteil dessen, was die Methode ReceiveBuffer empfängt.
Man kann sich bei HTTP nicht darauf verlassen, dass es immer einen Content-Length-Header gibt. Im allgemeinen ist das Ende dann, wenn die TCP-Verbindung geschlossen wird (außer bei Persistent Verbindungen ab HTTP/1.1, aber darum kümmern wir uns hier nicht). Dass die Verbindung geschlossen wurde, erkennst du daran, dass MSDN-Library durchsuchenrecv() die Länge 0 zurückgibt.

Ich weiß nicht, wozu das Sleep gut sein soll. Standardmäßig blockieren die Socket-Funktionen sowieso schon solange, bis Daten empfangen wurden. Außer sie wurden mit SetSockOpt in den nonblocking-Modus versetzt. Aber in dem Fall wäre das hier eine sehr instabile Frickelei.
  Mit Zitat antworten Zitat
Benutzerbild von Dalai
Dalai
Online

Registriert seit: 9. Apr 2006
1.684 Beiträge
 
Delphi 5 Professional
 
#5

AW: Schnellere Kommunikation mit einer Fritzbox

  Alt 13. Okt 2017, 15:42
Dass die Verbindung geschlossen wurde, erkennst du daran, dass MSDN-Library durchsuchenrecv() die Länge 0 zurückgibt.
Deswegen ja meine Änderung des Codes in die repeat -Schleife auf Basis des MS-Beispiels. Problem dabei: der zweite Schleifendurchlauf bleibt bei Aufruf der recv-Funktion stehen, d.h. die Verbindung wird eben nicht geschlossen, und der Aufruf von recv ist offensichtlich blockierend.

-----

Aber ich bin einen Schritt weiter. Mir ist aufgefallen, dass bei einem verkleinerten Sleep trotzdem teilweise noch Informationen ankommen, und zwar solche, die mittels POST in einem SOAP-Envelope angefragt wurden. Ein Blick in den Code offenbarte dann, dass bei solchen POST-Anfragen mit SOAP kein KeepAlive gesetzt wird, bei allen anderen schon:
Delphi-Quellcode:
function THTTPRequest.SendHeader: UTF8String;
[...]
      if Length(FHTTPSend.Soap.Namespace) = 0 then begin
        LHeader.Add(Format('Keep-Alive: %d', [KEEP_ALIVE]));
        LHeader.Add('Connection: Keep-Alive');
      end
      else
        LHeader.Add('Connection: Close');
Testweise habe ich die if-Bedingung auskommentiert und siehe da: es kommen alle Informationen an, auch mit einem Sleep(20); in TClient.ReceiveBuffer. Meine Schlussfolgerung: dem Server wurde im Header der Anfrage mitgeteilt, er soll die Verbindung offenhalten, was er offenbar auch tut. Deswegen wartet recv bis zum Empfang von Daten - also vermutlich "endlos".

Ich verstehe auch gar nicht, warum da ein KeepAlive angefordert wird. In THTTPRequest.Execute wird die Instanz von TClient unmittelbar nach dem Empfang der Daten sowieso zerstört - und der Socket damit ebenfalls geschlossen. Auszüge aus dem Code:
Delphi-Quellcode:
function THTTPRequest.Execute: Boolean;
[...]
SendStr := SendHeader + Params;
LClient := TClient.Create;
try
  if LClient.Connect then begin
    LClient.SendBuffer(SendStr, Length(SendStr));
    if (LClient.ReceiveBuffer > 0) then begin
      RcvdHeader(LClient.Header);
      RcvdContent(LClient.Content);
    end;
  end;
finally
  LClient.Free;
end;


destructor TClient.Destroy;
begin
  if FConnected then
      Disconnected;
  inherited;
end;

function TClient.Disconnected: Boolean;
begin
  Result := WinSock.shutdown(FSocket, SD_BOTH) = 0;
  if Result then begin
    FConnected := False;
    Result := WinSock.CloseSocket(FSocket) = 0;
  end;
end;
Wozu die Verbindung über KeepAlive offenhalten, wenn gleich danach der Socket geschlossen werden soll bzw. geschlossen wird

Grüße
Dalai
  Mit Zitat antworten Zitat
Namenloser

Registriert seit: 7. Jun 2006
Ort: Karlsruhe
3.724 Beiträge
 
FreePascal / Lazarus
 
#6

AW: Schnellere Kommunikation mit einer Fritzbox

  Alt 13. Okt 2017, 18:48
Ich habe den Source Code gerade mal überflogen. Es scheint, dass dort tatsächlich HTTP/1.1 eingesetzt wird. HTTP/1.1 ist etwas komplizierter als HTTP/1.0, da eine Verbindung hier dauerhaft aufrecht erhalten bleibt und für mehrere Requests wiederverwendet wird. Deshalb wird die Verbindung hier nicht geschlossen. Deshalb auch dieses ganze KeepAlive-Gedöhns. Ich persönlich würde das Protokoll der Einfachheit halber auf HTTP/1.0 ändern, da HTTP/1.1 im lokalen Netz sowieso kaum Vorteile hat. Ich weiß jetzt aber nicht, inwieweit sich das auf den Rest des Codes auswirken würde.
  Mit Zitat antworten Zitat
Benutzerbild von Dalai
Dalai
Online

Registriert seit: 9. Apr 2006
1.684 Beiträge
 
Delphi 5 Professional
 
#7

AW: Schnellere Kommunikation mit einer Fritzbox

  Alt 13. Okt 2017, 20:06
[...] da eine Verbindung hier dauerhaft aufrecht erhalten bleibt und für mehrere Requests wiederverwendet wird. Deshalb wird die Verbindung hier nicht geschlossen.
Sofern KeepAlive gesetzt ist, trifft das zu. Siehe meine weiteren Ausführungen in #6 oben.

Nach Entfernung der KeepAlive-Header wird die Verbindung geschlossen und der Abruf geht schnell; mein Testprogramm braucht dann weniger als eine Sekunde zum Starten, vorher waren es fast fünf (je nach Menge der abgerufenen Informationen).

Allerdings hänge ich immer noch an der Abbruch-Bedingung der repeat-Schleife. Ohne eine Verzögerung vor dem Aufruf von recv liefert selbiges keine Daten. Das derzeit benutzte Sleep(20); in der Schleife finde ich nicht so toll. OK, heute funktioniert es sogar ohne Sleep(), was gestern nicht ging. Hä? Ich werde das wohl beobachten müssen, ob es in den nächsten Tagen weiterhin funktioniert wie vorgesehen...

Grüße
Dalai
  Mit Zitat antworten Zitat
Antwort Antwort


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 23:57 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