Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Netzwerke (https://www.delphipraxis.net/14-netzwerke/)
-   -   Delphi XML-String über TCP empfangen (https://www.delphipraxis.net/91835-xml-string-ueber-tcp-empfangen.html)

Rungholt 10. Mai 2007 16:00


XML-String über TCP empfangen
 
Hi,

klingt simple, aber ich tu mich irgendwie schwer damit.
Hat jemand ein Beispiel, wie ich große Strings (XML)
per TCP-Komponente (vorzugsweise über WSocket, oder Indy) empfangen kann ?
Prinzipiell geht das bei mir, nur leider wird der XML-String, den ich über ein
Fremdprogramm empfange, so schnell abgefeuert, dass ich irgendwann nur noch einen
unvollständigen XML-String aus dem Buffer lese. Ich brauche den XML String natürlich
am Stück um ihn korrekt parsen zu können.

Danke schonmal für die Hilfe.

Gruß
Sascha

PS.: Benutze Delphi 7, Indy 7, ICS 7

Udontknow 10. Mai 2007 16:44

Re: XML-String über TCP empfangen
 
Hallo!

Du musst den String "in einem Stück" einlesen. Ich selber mache die gesamte Kommunikation eigentlich immer über Streams, die erst komplett empfangen werden und dann verarbeitet.

Im DF habe ich übrigens die SimpleTCP-Komponenten gepostet (basieren auf Indy), die dir da vielleicht auch ein bisschen Arbeit abnehmen.

Cu,
Udontknow

shmia 10. Mai 2007 16:52

Re: XML-String über TCP empfangen
 
Grundsätzlich werden Daten, die man über das Netzwerk verschickt in einzelne Pakete zerlegt.
TCP bzw. WinSock sorgt dafür, dass die Pakete vollständig und in richtiger Reihenfolge eintreffen.
Du selbst bist aber für das Zusammenhängen der Pakete verantwortlich.
Also muss dann im ReceiveEvent ungefähr folgende Zeile stehen:
Delphi-Quellcode:
   xmldata := xmldata + indySocket.ReceiveString;
// die Funktion ReceiveString hat möglicherweise einen anderen Namen
// ich hab mir nicht die Mühe gemacht die genaue Syntax herauszusuchen
Jetzt hast du vielleicht noch das Problem, dass du das Ende der Übertragung feststellen musst,
damit du dann auf die Daten reagieren kannst.
Entweder du schliest die TCP-Verbindung oder du übermittelst vorher die Anzahl der Nutzdaten.

Vergleiche das mit HTTP:
Code:
HTTP/1.1 200 OK
Server: Apache/1.3.29 (Unix) PHP/4.3.4
Content-Length: (Größe von info.xml in Byte)
Content-Language: de (nach ISO 639 und ISO 3166)
Content-Type: text/xml
<HTML> ....hier die Nutzdaten .....
In Content-Length wird die Länge der Nutzdaten übermittelt, damit der Browser weiss, wie viel er lesen muss.

Rungholt 11. Mai 2007 08:42

Re: XML-String über TCP empfangen
 
Danke für die Antworten, aber ich denke ich muss mir was anderes einfallsen lassen. Hier mal ein Beispiel, wie ich die
String-Pakete bekomme:

Paket 1)

<?xml version="1.0" encoding="UTF-16"?>
<DataCaptor ID="{88DB1901-08E1-4012-8EC6-1485E5C04438}">
<DDI ID="{16584EB1-55B2-4BCF-8F3E-48FCDD16769F}">
<TimeStamp ComputerTime="20070511093028.638">
<Variable VarID="58" Value="1160.000030137"/>
<Variable VarID="61" Value="7556.000030653"/>
<Variable VarID="536" Value="6934.000030088"/>
<Variable VarID="537" Value="9150.000018171"/>
.
.
.
</TimeStamp>
</DDI>
</DataCaptor>


Das erste Paket kommt vielleicht noch korrekt (kompletter XML-String)
Aber Irgendwann sieht ein Paket dann so aus:

Paket N)

<Variable VarID="4091" Value="324.000013657"/>
<Variable VarID="4092" Value="8652.00003048"/>
<Variable VarID="4108" Value="2174.000015699"/>
<Variable VarID="250" Value="2668.00001114"/>
</TimeStamp>
</DDI>
</DataCaptor>
<?xml version="1.0" encoding="UTF-16"?>
<DataCaptor ID="{88DB1901-08E1-4012-8EC6-1485E5C04438}">
<DDI ID="{908451A3-0B40-4079-ACCC-E0F28AA1557D}">
<TimeStamp ComputerTime="20070511093029.638">
<Variable VarID="801" Value="3455.000015483"/>
<Variable VarID="807" Value="690.000000182"/>


Und da ich eigentlich keinen Einfuss drauf habe, wie das Paket ankommt, kann ich vermutlich nichts anderes tun,
als immer ein paar Pakete sammeln und dann mit ein bisschen String-Verarbeitung vom ersten Anfangs-Tag bis zum letzten
Ende-Tag den gültigen XML-Bereich zu kopieren und den zu verarbeiten.

Oder sonst noch Ideen ? :gruebel:

Udontknow 11. Mai 2007 08:57

Re: XML-String über TCP empfangen
 
Wie gesagt, packe den String in einen Stream, schicke vorneweg die Size des Streams als Integer, und sende die Daten des Streams. Auf der Gegenseite weisst du genau, wieviele Bytes du nun für das Paket einzulesen hast.

Cu,
Udontknow

Rungholt 11. Mai 2007 09:00

Re: XML-String über TCP empfangen
 
Ich habe nur eine Seite. Ich bin nur der client und habe keinen Einfluß auf den ankommenden XML-String.
Dieser wird von einem externen Programm gesendet. Oder meinst du den ankommenden XML-String in einen Stream packen ? :gruebel:

Udontknow 11. Mai 2007 09:05

Re: XML-String über TCP empfangen
 
Ahso, hast gar keinen Einfluss auf den Sendemechanismus? Das ist tatsächlich was anderes. Dann würde ich es genauso, wie du vorgeschlagen hast, machen: Alles an einen String hängen und auf XML-Tags achten, anhand dieser dann die Pakete ausschneiden...

Cu,
Udontknow

Rungholt 11. Mai 2007 09:07

Re: XML-String über TCP empfangen
 
Richtiiiig. :zwinker:

Ich lass den Thread mal als "offen" stehen, bis ich mit der Implementierung fertig bin.
Vielleicht hat ja noch jemand ne Blitzidee.

Thanx !
Sascha

Muetze1 11. Mai 2007 09:10

Re: XML-String über TCP empfangen
 
Du brauchst keine Größenangabe, da du durch die XML Struktur immer feststellen kann, wann diese wieder vollständig (geschlossen ist). Dein grundlegendes Problem ist einfach nur, dass du mehrfach aufgerufen wirst, bis alle Daten empfangen wurden (bzw. du mehrfach Datan abholen musst). Dabei können die Daten an beliebiger Stelle getrennt werden. Von daher folgende Vorgehensweise:

1. Ein Buffer anlegen - am besten dynamisch. Es eignet sich z.B. ein TMemoryStream.
2. Alle abgeholten Datenpackete in diesen Stream schreiben (immer hinten dran)
3. Wenn du mal wieder was in den MemoryStream geschrieben hast, dann kannst du die Daten verarbeiten. Dazu musst du wissen, ob die Daten vollständig sind - und das kann dir dein XML Provider sagen. Der weiss genau, ob die XML Struktur vollständig ist (sprich: gibt es zum Hauptknoten-Tag auch ein schliessendes Tag). Wenn dies der Fall ist, weiss er auch wo die Daten eines XML Packetes aufhören. Damit kannst du diesen Teil vorne aus dem MemoryStream entfernen. Dieses so lange wiederholen bis der MemoryStream eine Grösse von 0 hat (Idealfall, alles interpretierbar, da alles vollständig) oder der XML Provider sagt, dass ist noch nicht vollständig.

So sollte der grundlegende Weg sein. Nun ist offen wie du deinen XML Provider entlocken kannst, wie gross die Daten sind und bis wo in dem Stream eine komplette, gültige Struktur geht und ob sie gültig (komplett) ist.

Die String selber parsen um das Ende zu ermitteln (ob es enthalten ist) wäre ein möglicher Schnellschluss. Wenn der Hauptknoten immer gleich heisst, dann kannst du fest nach dem Ende-Tag des Knotens im String suchen, selber aufteilen und aus dem Stream löschen und entsprechend auch einen schon fertig aufbereiteten Stream deinem XML Provider geben.

Rungholt 11. Mai 2007 09:20

Re: XML-String über TCP empfangen
 
Hi Muetze,

ja so in der Art hätte ich es realisiert.
Jetzt entdeckte ich aber glücklicherweise genau die richtige Methode in meiner Indy-Komponente,
die das Problem ganz alleine löst.

Delphi-Quellcode:
while IdTCPClient.Connected do begin
   Memo_Daten.Lines.Add(IdTCPClient.WaitFor('</DataCaptor>'));
   Application.ProcessMessages;
end;
Die Funktion "WaitFor" wartet solang, bis im Receive-Buffer das Ende-Tag </DataCaptor> zu finden ist
und holt erst dann die Daten. Genauso muss es sein. :thumb:


Danke an alle Beteiligten !
Sascha


Alle Zeitangaben in WEZ +1. Es ist jetzt 23:15 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