AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Netzwerke Stringlist mit SendStream versenden
Thema durchsuchen
Ansicht
Themen-Optionen

Stringlist mit SendStream versenden

Ein Thema von runningsoft · begonnen am 10. Feb 2017 · letzter Beitrag vom 11. Feb 2017
Antwort Antwort
Benutzerbild von runningsoft
runningsoft

Registriert seit: 8. Okt 2004
Ort: Bernau
108 Beiträge
 
Delphi 10.4 Sydney
 
#1

Stringlist mit SendStream versenden

  Alt 10. Feb 2017, 22:59
Hallo zusammen,

ich sitze schon ewig über der Aufgabe einen Record, der neben einigen festen Strings und Integerwerten auch eine Stringlist enthält, über TClientSocket bzw. TServerSocket zu versenden bzw. zu empfangen. Leider bisher ohne Erfolg. Lasse ich die Stringliste testweise aus meinem Record heraus, funktioniert das versenden des Records vom Client an den Server wunderbar. Versende ich das ganze mit der Stringliste gibts am Server sofort eine Exception, sobald ich versuche auf den Inhalt der übertragenen Stringliste zuzugreifen.

Hier mal ein bisschen Code:
Delphi-Quellcode:
type
CustomRec = record
   RecID : Integer;
   RecVorgang : String[15];
   RecStatus: integer;
   ....
   RecTNListe: TStringList;
   end;
Erstellen und versenden des Records am Client:
Delphi-Quellcode:
procedure TClientForm.BitBtn1Click(Sender: TObject);
var MyTNList : TStringList;
    MStr : TMemoryStream;

begin
....
Finalize(Rec); //Record zur Sicherheit komplett leeren
Rec.RecListe := TStringList.Create; //Stringliste des Records erzeugen
with Rec do
   begin
   RecID := GetClientID;
   RecVorgang := 'Irgendwas';
   RecStatus := 2;
   .....
   RecTNListe.Text := MyTNList.Text; //MyTNList wurde vorher created und enthält Daten
   end;
//als Stream versenden
MStr := TMemoryStream.Create;
  try
  MStr.Write(Rec,SizeOf(Rec));
  MStr.Position := 0;
  Form5.ClientSocket1.Socket.SendStream(MStr);
  finally
  if Assigned(MStr) then
    begin
    MStr := nil;
    MStr.Free;
    end;
  end;
end;
Und hier noch die Empfangsprozedur am Server:
Delphi-Quellcode:
procedure TServerForm.ServerSocket1ClientRead(Sender: TObject;Socket: TCustomWinSocket);
var ....
    iLen: integer;
    Rec : CustomRec;
    Bfr : Pointer;
begin
Finalize(Rec);
Rec.RecListe := TStringList.Create; //Stringliste des Records erzeugen
//Länge des Streams empfangen
iLen := Socket.ReceiveLength;
//Arbeitsspeicher reservieren
GetMem(Bfr, iLen);
//Stream empfangen und in Arbeitsspeicher schreiben
   try
   Socket.ReceiveBuf(Bfr^, iLen);
   //Position auf das Ende des Streams setzen
   MStream.Seek(0,soFromEnd);
   MStream.Write(Bfr^, iLen);
   finally
   FreeMem(Bfr);
   end;
MStream.Seek(0,soFromEnd);
//an erste Position gehen
MStream.Position := 0;
//Buffer in Record einlesen
MStream.ReadBuffer(Rec,iLen);

//wenn ich jetzt auf die Stringliste des Records zugreifen will, gibts eine Exception
//die Anzeige der Strings oder Integerwerte des Records funktioniert dagegen problemlos
//lasse ich Server und Client testweise auf ein und dem selben Rechner laufen, funktioniert es wunderbar
showmessage(Rec.RecTNListe.Strings[0]);
...
end;
Es scheint so, dass ich nicht wirklich die Stringliste per Sendstream übertrage, obwohl diese am Client definitv in den Record geschrieben wird, sondern nur Pointer auf die Adressen der Daten der Stringliste. Da der (entfernte) Server diese Adressen des Clients nicht kennt, kommt die Exception.

Die Frage ist also, wie bekomme ich den INHALT der Stringliste übertragen und auch wieder ausgelesen?

Danke schon mal für Eure Mithilfe.
  Mit Zitat antworten Zitat
mjustin

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

AW: Stringlist mit SendStream versenden

  Alt 10. Feb 2017, 23:38
Was nicht passt, wird passend gemacht: um eine Datenstruktur über Sockets (Streams) zu senden und zu empfangen, wird sie in ihre Teile zerlegt und jeweils aus diesen Teilen wieder zusammengesetzt. Wenn Sender und Empfänger den Strukturaufbau genau kennen, braucht der Empfänger nur die eintreffenden Daten in der richtigen Reihenfolge einzulesen.

Sehr einfach geht das mit den Read- und Write Funktionen aus Indy, die im IdTCPClient.IOHandler zur Verfügung stehen. Dinge mit flexibler Länge wie Strings oder Byte Arrays senden dabei zuerst die Länge und dann den Inhalt. So weiss der IOHandler des Empfängers, wie viele Bytes er lesen muss.

Diese Zerlegung auf primitive Objekte, die einzeln übertragen werden, ist sehr low-level und oft ausreichend. Für flexiblere Strukturen sind XML oder JSON als Zwischenformat geeigneter, da Sender und Empfänger alles als einen einzigen String senden und empfangen. Lediglich ein XML oder JSON Parser wird dazu noch benötigt.
Michael Justin
habarisoft.com
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

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

AW: Stringlist mit SendStream versenden

  Alt 11. Feb 2017, 00:13
Du versendest nur den Zeiger auf das Objekt und wunderst dich dann zurecht, dass am Ziel der Zeiger nur auf Schrott zeigt?

String[15] ist ein ShortString, also ein Record und liegt somit komplett innerhalb des Speichers deines eigenen Records.
Hättest du String verwendet, wäre dir dort das Selbe passiert.

Du darfst also nicht den Zeiger versenden, sondern mußt den Text-Inhalt manuell einzeln versenden und drüben in eine neue TStringList kopieren.
Garbage Collector ... Delphianer erzeugen keinen Müll, also brauchen sie auch keinen Müllsucher.
my Delphi wish list : BugReports/FeatureRequests

Geändert von himitsu (11. Feb 2017 um 00:26 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von runningsoft
runningsoft

Registriert seit: 8. Okt 2004
Ort: Bernau
108 Beiträge
 
Delphi 10.4 Sydney
 
#4

AW: Stringlist mit SendStream versenden

  Alt 11. Feb 2017, 08:56
Genau das ist ja mein Problem. Wie bekomme ich den Inhalt der Stringlist versendet und nicht nur den Zeiger darauf.

Ich hatte es zwischenzeitlich über TByteArray versucht. Ich habe die Stringlist also Byte für Byte in das Bytearray eingelesen und versendet. Hat auch funktioniert, hat allerdings den Nachteil, dass das Bytearray ein statisches Array ist und eine feste Größe von 32767 Byte hat, die Stringlistes aber nicht annähernd diese Größe erreicht. Ist also nicht so ganz befriedigend.

Anschließend hab ich es mit einem dynamischen Array aus TBYTE versucht. Da das aber ein dynamisches Array ist, stehe ich vor dem gleichen Problem wie mit der Stringlist, es werden nur die Zeiger versendet, nicht aber der Inhalt.

Für einen Tipp und ein paar Codeschnipsel, wie ich den Inhalt der Stringlist auf der Clientseite aufbereiten muss, um ihn zu versenden und auf der Serverseite wieder in eine Stringliste hineinbekomme, wäre ich dankbar.
  Mit Zitat antworten Zitat
Benutzerbild von dummzeuch
dummzeuch

Registriert seit: 11. Aug 2012
Ort: Essen
1.466 Beiträge
 
Delphi 10.2 Tokyo Professional
 
#5

AW: Stringlist mit SendStream versenden

  Alt 11. Feb 2017, 09:28
Genau das ist ja mein Problem. Wie bekomme ich den Inhalt der Stringlist versendet und nicht nur den Zeiger darauf.
Ich wuerde stringlist.Text versenden. Beim Emfpaenger dann im neuen Record eine Stringlist anlegen (der dort gespeicherte Pointer ist ja ungueltig, also einfach eine neue erzeugen und zuweisen) und dieser den empfangenen Text zuweisen.
Thomas Mueller
  Mit Zitat antworten Zitat
samso

Registriert seit: 29. Mär 2009
439 Beiträge
 
#6

AW: Stringlist mit SendStream versenden

  Alt 11. Feb 2017, 15:42
Du kannst den Record nicht komplett senden, sondern musst den String gesondert behandeln. Die Stringliste ist dann nicht mehr Bestandteil des Records, sondern wird mit einem zweiten Schreibbefehl zu dem MemoryStream hinzugefügt. Auf der Empfangsseite muss das Ganze wieder entsprechend zerlegt werden.
Delphi-Quellcode:
  
type
CustomRec = record
   RecID : Integer;
   RecVorgang : String[15];
   RecStatus: integer;
   ....
   RecStrLen: Integer; //<- damit weiß ich auf der Empfangsseite wie lang der der nachfolgende Text ist
  end;
...
  temp := Stringlist.Text;
  RecStrLen := Length(temp);
  MStr.Write(Rec,SizeOf(Rec));
  MStr.Write(Pointer(temp)^, Length(temp));
  MStr.Position := 0;
  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 07:38 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