Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Netzwerke (https://www.delphipraxis.net/14-netzwerke/)
-   -   Delphi Indy TCP Client/Server: spontan Nachricht an den Server senden? (https://www.delphipraxis.net/175252-indy-tcp-client-server-spontan-nachricht-den-server-senden.html)

romber 9. Jun 2013 16:34

Indy TCP Client/Server: spontan Nachricht an den Server senden?
 
Hallo!

Ich habe einen TCP-Server, der von einem Webservice große Mengen an Daten bezieht und diese Daten ohne Verzögerunf an die Clients weiterleitet. Bis jetzt wurde die Client-Server-Kommunikation so aufgebaut, dass der Client nur unmittelbar nach der Herstellung der Verbindung die Daten an den Server sendet. Der Server pfüft die Daten. Sind die Daten in Ordnung, startet eine while-Schleife, die den Datencontainer des Clients überwacht und neue Daten sofort übermittelt. Ab diesem Moment sendet det Client gar nichts mehr an den Server.

Nun soll der Client gelegentlich auch etwas an den Server verschicken. Wenn in meiner Schleife mit ReadLn auf die Daten vom Client warte, verzögert sich die Übermittlung der Daten an den Client. Wie lasse ich auf dem Server die Daten empfangen, ohne dass sich der Sendeprozess verzögert?

mjustin 9. Jun 2013 17:32

AW: Indy TCP Client/Server: spontan Nachricht an den Server senden?
 
Zitat:

Zitat von romber (Beitrag 1217942)
Wenn in meiner Schleife mit ReadLn auf die Daten vom Client warte, verzögert sich die Übermittlung der Daten an den Client. Wie lasse ich auf dem Server die Daten empfangen, ohne dass sich der Sendeprozess verzögert?

Bei Indy zum Beispiel etwa so, die Prozedur wird dann einfach von Zeit zu Zeit innerhalb der while Schleife aufgerufen:

Delphi-Quellcode:
procedure CheckForClientData(const IOHandler: TIdIOHandler);
begin
if IOHandler.InputBufferIsEmpty then
begin
  // sind Daten vorhanden?
  IOHandler.CheckForDataOnSource(10); // blockiert maximal 10 Millisekunden
  if IOHandler.InputBufferIsEmpty then
    Exit;
end;

// Daten sind vorhanden: jetzt darf man (blockierend) die Client-Daten lesen
ClientData := IOHandler.ReadLn(ATimeOut);
// verarbeite Client-Daten
  ...
end;

romber 9. Jun 2013 19:28

AW: Indy TCP Client/Server: spontan Nachricht an den Server senden?
 
Zitat:

Zitat von mjustin (Beitrag 1217947)
Bei Indy zum Beispiel etwa so, die Prozedur wird dann einfach von Zeit zu Zeit innerhalb der while Schleife aufgerufen

Zeit zu Zeit bedeutet aber, dass ich dass wirklich nur Zeit zu Zeit aufrufen muss, oder?
Wenn ich z.B. jede 10 Sekunden den InputBuffer prüfe und der Client innerhalb des Intervals etwas schickt, wirkt sich das negativ auf das Senden der Daten aus? Mir ist halt sehr wichtig, dass das Senden nicht beeinträchtigt wird.

Mavarik 9. Jun 2013 20:51

AW: Indy TCP Client/Server: spontan Nachricht an den Server senden?
 
2. Verbindung auf einem anderen Port?

Mavarik

romber 9. Jun 2013 21:07

AW: Indy TCP Client/Server: spontan Nachricht an den Server senden?
 
Zitat:

Zitat von Mavarik (Beitrag 1217965)
2. Verbindung auf einem anderen Port?

Es muss unbedingt dieselbe Verbindung sein, die der Dateübertragung zum Client dient.

mjustin 10. Jun 2013 07:42

AW: Indy TCP Client/Server: spontan Nachricht an den Server senden?
 
Zitat:

Zitat von romber (Beitrag 1217955)
Zitat:

Zitat von mjustin (Beitrag 1217947)
Bei Indy zum Beispiel etwa so, die Prozedur wird dann einfach von Zeit zu Zeit innerhalb der while Schleife aufgerufen

Zeit zu Zeit bedeutet aber, dass ich dass wirklich nur Zeit zu Zeit aufrufen muss, oder?
Wenn ich z.B. jede 10 Sekunden den InputBuffer prüfe und der Client innerhalb des Intervals etwas schickt, wirkt sich das negativ auf das Senden der Daten aus? Mir ist halt sehr wichtig, dass das Senden nicht beeinträchtigt wird.

Die zehn Millisekunden Verzögerung bei CheckForDataOnSource könnten bei sehr zeitkritischen Anwendungen ein Problem darstellen, wenn sie sehr oft (in kurzen Intervallen) dazwischenfunken. Entweder ruft man die Prozedur dann nur z.B. jeden n-ten Durchlauf der Sendeschleife auf, oder - aber das ist ein wenig aufwendiger - man verlegt die Prozedur in einen eigenen Thread. Die beiden Streams des Sockets können von zwei verschiedenen Threads gleichzeitig benutzt werden - ein Sende-Thread, ein CheckForData-Thread. (Bei Synapse geht das nicht, wegen Verwendung von class-Variablen, aber mit Indy ist es im Prinzip möglich laut Remy Lebeau).

BUG 10. Jun 2013 09:48

AW: Indy TCP Client/Server: spontan Nachricht an den Server senden?
 
Vielleicht könnte man mit select auch ohne zweiten Thread auskommen. Keine Ahnung wie Indy (uÄ) das unterstützen.

Mögliches Vorgehen:
  1. mit select auf Sende- und Empfangsrichtung warten
  2. In den Socket schreiben bzw. daraus lesen (jeweils nicht blockierend). In der zu bevorzugenden Richtung machst dabei weiter, bist du nicht mehr kannst, in der anderen Richtung verarbeitest du nur einen kleinen Buffer (wenn überhaupt).
  3. zurück zu 1.

Mit nicht-blockierenden Socketoperation lässt sich viel anstellen :mrgreen:

romber 10. Jun 2013 10:22

AW: Indy TCP Client/Server: spontan Nachricht an den Server senden?
 
Zitat:

Zitat von mjustin (Beitrag 1217986)
...Entweder ruft man die Prozedur dann nur z.B. jeden n-ten Durchlauf der Sendeschleife auf, oder - aber das ist ein wenig aufwendiger - man verlegt die Prozedur in einen eigenen Thread. Die beiden Streams des Sockets können von zwei verschiedenen Threads gleichzeitig benutzt werden - ein Sende-Thread, ein CheckForData-Thread.

Was bedeutet "aufwendiger" in diesem Fall? Nur dass ich einen neuen Thread abspalten muss, der auf IOHandler des Sockets zugreift oder muss ich da unbedingt noch was beachten? Muss ich die Zugriffe auf IOHandler sychnronisieren? Oder kann ich auf die Streams einzeln zugreifen?

Zitat:

Zitat von BUG (Beitrag 1218004)
Vielleicht könnte man mit select auch ohne zweiten Thread auskommen. Keine Ahnung wie Indy (uÄ) das unterstützen.

Mögliches Vorgehen:
  1. mit select auf Sende- und Empfangsrichtung warten
  2. In den Socket schreiben bzw. daraus lesen (jeweils nicht blockierend). In der zu bevorzugenden Richtung machst dabei weiter, bist du nicht mehr kannst, in der anderen Richtung verarbeitest du nur einen kleinen Buffer (wenn überhaupt).
  3. zurück zu 1.

Mit nicht-blockierenden Socketoperation lässt sich viel anstellen :mrgreen:

Ich darf in der bereits bestehener Routine nicht viel verändern. Einen neuen Thread oder eine zusätzliche Prozedur, die ab und zu aufgerufen wird wäre noch kein Problem. Aber vielen Dank für den Vorschlag.

mjustin 10. Jun 2013 12:13

AW: Indy TCP Client/Server: spontan Nachricht an den Server senden?
 
Zitat:

Zitat von romber (Beitrag 1218008)
Was bedeutet "aufwendiger" in diesem Fall? Nur dass ich einen neuen Thread abspalten muss, der auf IOHandler des Sockets zugreift oder muss ich da unbedingt noch was beachten? Muss ich die Zugriffe auf IOHandler sychnronisieren? Oder kann ich auf die Streams einzeln zugreifen?

Der Hauptaufwand liegt darin, dass durch einen zweiten Thread (der nur für das Empfangen von Daten zuständig ist) bedingt wird, die Kommunikation mit dem Hauptthread threadsicher zu gestalten. Der erforderliche Aufwand hängt davon ab, wie komplex die notwendige Kommunikation zwischen dem Hauptthread und dem Lesethread ist.

Der IOHandler wird unsynchronisiert verwendet (zu synchronisieren würde den Vorteil des zweiten Threads wieder aufheben. Der schreibende Thread darf dann aber auch nie lesen - sollte das erforderlich sein, muss synchronisiert werden damit nicht zwei Threads lesen.

romber 10. Jun 2013 12:49

AW: Indy TCP Client/Server: spontan Nachricht an den Server senden?
 
Zitat:

Zitat von mjustin (Beitrag 1218022)
Der Hauptaufwand liegt darin, dass durch einen zweiten Thread (der nur für das Empfangen von Daten zuständig ist) bedingt wird, die Kommunikation mit dem Hauptthread threadsicher zu gestalten. Der erforderliche Aufwand hängt davon ab, wie komplex die notwendige Kommunikation zwischen dem Hauptthread und dem Lesethread ist.

Sehr kompliziert muss es nicht sein. Beim erfolgreichen Login wird ein Client-Object erzeugt, der neben der Referenz auf den IdContext des Sockets noch eine zusätzliche Variable für den neuen Thread enthält. Dieser Objekt wird wiederrum an IdContext des Sockets angehängt. Dann erstelle ich den Lesethread und lasse ihr auf die IdContext-Referenz des Hauptthreads zugreifen. Beim Freigeben des Hauptthreads prüfe ich, ob Lesethread existiert und beende ihn. Wäre das so threadsicher oder habe ich was vergessen?

Muss ich in beiden Threads aud IOHandler zugreifen oder kann ich irgendwie direkt auf Lese- bzw. Schreibstrem zugreifen?


Alle Zeitangaben in WEZ +1. Es ist jetzt 23:32 Uhr.
Seite 1 von 2  1 2      

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