Autor Beitrag
Dolognio
Hält's aus hier
Beiträge: 12



BeitragVerfasst: Fr 03.11.06 11:26 
Hi @ all.

Ich habe hier im Forum gelesen wie ich in einen Stream ein Identifikationsmerkmal schreiben kann, um zu erkennen, was für ein Datentyp sich in dem Stream befindet. Das klappt auch ohne Compilerfehler.

Meine Frage ist jetzt allerdings: Wie kann ich den Stream nach Empfang wieder so aufteilen, dass erst der erste Teil ausgelesen wird mit dem Merkmal, und dann der Rest dem Datentyp entsprechend? Ich kann mir da absolut nichts drunter vorstelln.

Thx schonmal.
Udontknow
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2596

Win7
D2006 WIN32, .NET (C#)
BeitragVerfasst: Fr 03.11.06 11:58 
Hallo!

Du musst nicht aufteilen. Du ermittelst mit einem Aufruf von

ausblenden Delphi-Quelltext
1:
Stream.ReadBuffer(ID,SizeOf(ID));					


das Identifikationsmerkmal. Anschliessend reagierst du.

ausblenden Delphi-Quelltext
1:
2:
3:
4:
if ID=ID_JPG then 
  Picture.LoadFromStream(Stream);
if ID=ID_Text then
  Memo.Lines.LoadFromStream(Stream);


Erst wenn du "hinter" den JPG-Daten auch noch andere Blöcke sendest, wird es schwieriger. Dann musst du einen temporären Stream hinzunehmen und zusätzlich in den Originalstream auch noch die Größe des Blocks schreiben, damit die Blöcke auseinanderzuhalten sind.

Cu,
Udontknow
Dolognio Threadstarter
Hält's aus hier
Beiträge: 12



BeitragVerfasst: Fr 03.11.06 16:17 
OK, thx, ich probier des mal so. Mla schauen ob ich des hinkrieg^^.

Cya.


PS: Thread lass ich für evtl weitere Fragen zum Thema ma noch offen bzw. unmarkiert.
Dolognio Threadstarter
Hält's aus hier
Beiträge: 12



BeitragVerfasst: Fr 03.11.06 18:11 
Hmm, also funzt doch noch nicht wie gewünscht, ka was jetzt wieder los ist. Erst ma der Code:

ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
const ID_String = 0;
const ID_Stringlist = 1;

procedure Testsenden;
var sl: TStringlist;
    stream1, stream2: TMemoryStream;
    ID: integer;
begin
  sl:= TStringlist.Create;
  Stream2:= TMemoryStream.Create;
  sl.Sorted:= false;
  sl.Clear;
  sl.BeginUpdate;
  try
      sl.add('string1');
      sl.add('string2');
      sl.add('string3');
      sl.add('string4');
      sl.add('string5');
      sl.add('string6');
      sl.add('string7');
      sl.add('string8');
      sl.EndUpdate;
      sl.SaveToStream(stream2);

      stream1:= TMemoryStream.Create;
      try
      //Identifikationsmerkmal in Stream schreiben
      ID:=ID_Stringlist;
      Stream1.WriteBuffer(ID,SizeOf(ID));
          try
            stream1.CopyFrom(stream2,stream2.Size)          //hier ist der Fehler "Stream Read Error"
          finally
            stream2.Free;
            MainFrm.TCPClient.SendStream(stream1);
          end;
      finally
      stream1.Free;
      end;
  finally
      sl.Free;
  end;
end;


Ich dachte egtl ich hab alles richtig gemacht, find kein Fehler, außer mn muss im Zusammenhang mit einer Stringliste noch was andres beachten beim Speichern in Stream. Jedenfalls bringt der Debugger zur Laufzeit den Fehler "Stream read error!" in der oben markierten Zeile.

Hoffentlich weißt du noch weiter :( :?:
Narses
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Administrator
Beiträge: 10183
Erhaltene Danke: 1256

W10ent
TP3 .. D7pro .. D10.2CE
BeitragVerfasst: Fr 03.11.06 18:25 
Moin!

Du mußt Stream2 auch wieder "zurückspulen". ;) So: Stream2.Position := 0;

cu
Narses

_________________
There are 10 types of people - those who understand binary and those who don´t.
Martok
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 3661
Erhaltene Danke: 604

Win 8.1, Win 10 x64
Pascal: Lazarus Snapshot, Delphi 7,2007; PHP, JS: WebStorm
BeitragVerfasst: Fr 03.11.06 18:31 
Oder statt Stream2.Size 0 angeben:
ausblenden Delphi-Quelltext
 
32:
{ ... }
      stream1.CopyFrom(stream2,0); //gesamten Stream2 kopieren

_________________
"The phoenix's price isn't inevitable. It's not part of some deep balance built into the universe. It's just the parts of the game where you haven't figured out yet how to cheat."
Dolognio Threadstarter
Hält's aus hier
Beiträge: 12



BeitragVerfasst: Fr 03.11.06 23:38 
Danke, jetzt klappts endlich, hätt ich in der Delphi-Hilfe geschaut über stream.copyfrom(), hätt ich gewusst dass ich ne 0 einfügen muss^^.

Wenn ich jetzt allerdings 2 verschiedene Merkmale in einen Stream einbauen muss, gilt dann das, was UDontKnow vorhin ma gesagt hat?

user profile iconUdontknow hat folgendes geschrieben:

Erst wenn du "hinter" den JPG-Daten auch noch andere Blöcke sendest, wird es schwieriger. Dann musst du einen temporären Stream hinzunehmen und zusätzlich in den Originalstream auch noch die Größe des Blocks schreiben, damit die Blöcke auseinanderzuhalten sind.



Und wenn ja, wie sieht dass denn dann aus? Was für Blöcke??? Und temporärer Stream ist TMemoryStream oder?
Udontknow
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2596

Win7
D2006 WIN32, .NET (C#)
BeitragVerfasst: Sa 04.11.06 21:59 
Hier die grobe Vorgehensweise. Ich gehe davon aus, daß jeder "Block" eine ID und eine Size mitgibt. Für jeden Block wird dann ein Stream bereitgestellt und die Funktion VerarbeiteBlock aufgerufen

ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
procedure VerarbeiteBlock(ID:Integer; Size:Integer; Stream:TStream);
begin
  //Hier Stream verarbeiten
end;

procedure VerarbeiteBloecke(Stream:TStream);
var ID:Integer;
var Size:Integer;
var TempStream:TMemoryStream;
begin
  //Für alle Blöcke Verarbeitungsroutine aufrufen
  While Stream.Position<Stream.Size do
  begin
    //Identifikation des nun folgenden Blocks auslesen
    Stream.ReadBuffer(ID,SizeOf(ID));
    //Grösse des nun folgenden Blocks auslesen
    Stream.ReadBuffer(Size,SizeOf(Size));

    //Temporären Stream erzeugen
    TempStream:=TMemoryStream.Create;
    try
      //Größe des Streams einstellen
      TempStream.Size:=Size;
      //Daten des Blocks aus Originalstream kopieren
      TempStream.CopyFrom(Stream,Size);
      //Position zurücksetzen für Lesezugriff
      TempStream.Position:=0;
      //Aufruf der Verarbeitungsroutine
      VerarbeiteBlock(ID,Size,TempStream);
    finally
      TempStream.Free;
    end;
  end;
end;


Cu,
Udontknow
Dolognio Threadstarter
Hält's aus hier
Beiträge: 12



BeitragVerfasst: Sa 04.11.06 23:38 
Also sry, aber ich werd aus deinem Code nich schlau.

Was versteht man denn überhaupt unter einem "Block"?
Und ich denk ma dass deine beiden Prozeduren zum lesen des gesendeten Streams da sind.

Wie aber speicher ich einen solchen Stream ab?

Einfach

ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
var sl: TStringlist;
    TempStream1, TempStream2, SLstream: TMemoryStream;
    ID: integer;
begin
  sl:= TStringlist.Create;
  SLstream:= TMemoryStream.Create;
  try
      //sl bearbeiten
      sl.SaveToStream(SLstream);

      TempStream2:= TMemoryStream.Create;
      try
      //Identifikationsmerkmal in Stream schreiben
      ID:= ID_Stringlist;
      Stream1.WriteBuffer(ID,SizeOf(ID));
        
          try
            TempStream2.CopyFrom(SLstream,0);
            TempStream1:= TMemoryStream.Create;
            
            try
              TempStream1.CopyFrom(TempStream2,0);
            finally
              SLStream.Free;

          finally
            TempStream2.Free;


          end;
      finally
      MainFrm.TCPClient.SendStream(TempStream1);
      TempStream1.Free;
      end;
  finally
      sl.Free;
  end;

end;


?? Oder wie sonst?
Und wie gibt man einem "Block" (was auch immer das jetzt ist) ID und Size mit?
Udontknow
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2596

Win7
D2006 WIN32, .NET (C#)
BeitragVerfasst: So 05.11.06 17:33 
Nun, ein Block ist für mich eben ein Paket zusammenhängender Daten.

Beispiel:

Du hast ein Chatprogramm geschrieben, über das du mal Text, mal aber auch ein Bild senden kannst. Nun tritt es ab und zu auf, daß Pakete aneinanderhängen, diese müssen also von dir auseinandergehalten werden. Das erreichst du, indem du die Struktur eben wie beschrieben aufbaust. Immer wenn der User ein Bild senden will, werden zuerst das Merkmal für "Bild", dann die Anzahl der Bytes für das Bild und anschliessend die Daten des Bildes gesendet. Die Empfangsroutine kann anhand des Headers (ID und Groesse) eben erkennen, wo ein Block endet und der nächste beginnt.

Cu,
Udontknow
Dolognio Threadstarter
Hält's aus hier
Beiträge: 12



BeitragVerfasst: Mo 06.11.06 00:30 
Hmm, also mit Streams muss ich mich glaub erst ma richtig befassen. Hab da noch nich so den Durchblick.
Hab mir daher jetzt auch was andres überlegt, wie ich 2 Merkmale in einen Stream schreiben kann.
Hier der Code:

Sender:
ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
procedure Testsenden;
var sl: TStringlist;
    stream1, stream2: TMemoryStream;
    ID: integer;
begin
  sl:= TStringlist.Create;
  Stream2:= TMemoryStream.Create;
  sl.Sorted:= false;
  sl.Clear;
  sl.BeginUpdate;
  try

//Stringlist füllen

      sl.EndUpdate;
      sl.SaveToStream(stream2);

      stream1:= TMemoryStream.Create;
      try
      //Identifikationsmerkmal in Stream schreiben
      ID:= 15;

      Stream1.WriteBuffer(ID,SizeOf(ID));
          try
            stream1.CopyFrom(stream2,0)
          finally
            stream2.Free;
            MainFrm.TCPClient.SendStream(stream1);
          end;
      finally
      stream1.Free;
      end;
  finally
      sl.Free;
  end;
end;


und
Empfänger:
ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
const ID_StringList = '1';
const ID_String = '2';

const ID_Frame1 = '1';
const ID_Frame2 = '2';
const ID_Frame3 = '3';
const ID_Frame4 = '4';
const ID_Frame5 = '5';
//...

procedure TForm1.TCPServerInput(Connection: TSimpleTCPConnection;
  Stream: TStream; var DisposeStream: Boolean);
var sl: TStringList;
    TypID, FrameID: char;
    ID: integer;
    h: string;
begin
   stream.ReadBuffer(ID,sizeof(ID));
   h:= inttostr(ID);
   TypID:= h[1];
   FrameID:= h[2];

   if TypID = ID_StringList then
   begin
      sl:= TStringList.Create;
      try
        sl.LoadFromStream(stream);
        if FrameID = ID_Frame5 then
           Frame5.ListBox1.Items.Assign(sl);
      finally
        sl.Free;
      end;
   end;
end;


Ist vielleicht nicht so sauber, aber funktioniert. Trotzdem DANKE für eure Geduld mir das alles näherzubringen!! :wink: :lol: