Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Netzwerke (https://www.delphipraxis.net/14-netzwerke/)
-   -   Delphi ClientSocket steam verschicken mit vorherigen Zeichen (https://www.delphipraxis.net/107368-clientsocket-steam-verschicken-mit-vorherigen-zeichen.html)

gandime 26. Jan 2008 14:48


ClientSocket steam verschicken mit vorherigen Zeichen
 
Hi,
ich möchte einen Stream verschicken:
Delphi-Quellcode:
var
  cs: TClientSocket;
  FStream:TFileStream;
begin
  cs.Socket.SendStream(FStream);
end;
wie kann ich jetzt hier
Delphi-Quellcode:
procedure TForm1.csWrite(Sender: TObject; Socket: TCustomWinSocket);
begin

end;
bevor das erste Stück des Stream verschickt wird Zeichen hinzufügen
also z.B. 'File-000001:' und im Anschluss dann das Stück vom Stream?

und eine Weitere frage: wie kann man bei der csWrite Procedure herausfinden um welchen Stream es sich handelt, wenn man mehrere gleichzeitig verschickt?

mfg
gandime

Muetze1 26. Jan 2008 17:18

Re: ClientSocket steam verschicken mit vorherigen Zeichen
 
Tipp: Stell dich doch mal mit einem Brechpunkt in die csWrite Methode rein und schau überhaupt erstmal, ob diese Methode überhaupt aufgerufen wird. Afair nicht.

gandime 26. Jan 2008 18:04

Re: ClientSocket steam verschicken mit vorherigen Zeichen
 
ok sry das ist mir auch gerade aufgefallen...
ich hab mir jetzt mal die buffergröße rausgesucht die bei sendstream benutzt wurde:
Delphi-Quellcode:
procedure TForm1.Button1Click(Sender: TObject);
var
  Fstream:TFileStream;
  Buffer: array[0..4095] of Byte;
begin
  Fstream:=TFileStream.Create('D:\a.mp3', fmOpenRead or fmShareDenyWrite);
  Fstream.read(Buffer,sizeof(Buffer));
  cs.Socket.SendBuf(Buffer,sizeof(Buffer));
aber die Server Procedure ClientRead wird erst bei dem zweiten mal drücken ausgeführt!
Jetzt sind meine Bedenken das wenn mehrere dateien gleichzeitig geschickt werden das diese durcheinander kommen können.
Deshalb die Frage ob die ClientRead Procedure zweimal ausgelöst wird oder die Daten einfach hintereinander in einem ankommen?
Deses passiert ja nur da die Daten erst verschickt werden wenn genug vorhanden sind oder wenn eine gewisse Zeit vergangen ist

Muetze1 26. Jan 2008 18:45

Re: ClientSocket steam verschicken mit vorherigen Zeichen
 
Wenn du zweimal nacheinander SendStream aufrufst, dann kommen die Daten von den jeweiligen Streams in vielen unterschiedlichen Größen und Aufrufen bei deinem ClientRead an - aber in der gleichen Reihenfolge und somit nacheinander folgend. Somit kannst du mit einem OnClientRead das Ende von dem ersten Stream zusammen mit dem Anfang des zweiten Streams empfangen.

Nur damit es später wieder darauf hinausläuft: Dein OnClientRead wird so oft aufgerufen, wie Daten empfangen wurden. Die Teilung dieser Aufrufe und der schon empfangenen Datentypen sind zufällig und entsprechen nicht der Teilung beim Aufruf zum Versenden. Sprich: Wenn du mit SendStream oder SendText irgendwas losschickst, dann ist nicht mal ansatzweise gesagt, dass du diesen als einen Block im OnClientRead wieder empfängst. Somit: Du kannst mehrfach im OnClientRead aufgerufen werden, bis du den gesendeten Text bzw. Daten wieder in einem Stück zusammen hast.

d1ng0d0gt0r 26. Jan 2008 19:34

Re: ClientSocket steam verschicken mit vorherigen Zeichen
 
Das ganze soll ja eigendlich so von Statten gehen:

Ich lese die Daten beim Client ein wie es gandime oben gezeigt hat, merke mir die Position bis zu der die letzten Bytes gelesen wurden und versende die Bytes dann. Dann fang ich wieder an ab der Stelle bis zu der bereits eingelesen wurde und lese wieder ein paar Bytes ein, diese versende ich wieder.
Das ganze so oft bis das Ende der Datei erreicht wurde.

Beim Server werden nun die Daten zusammen gesetzt, im OnClientRead Event.

Wenn ich mich recht entsinne war es nur bei UDP so das es Zufall ist ob die Daten in der richtigen Reihenfolge-, und ob die Daten überhaupt, ankommen.

TCP sollte es eigendlich gewähleisten das die Daten in Ein und der Selben Reihenfolge ankommen.
So war es damals bei VisualBasic6.

Dort habe ich das, wie oben beschrieben, verwirklicht.

http://www.tippscout.de/internet-was...tipp_2268.html

Zitat:

TCP leistet Aufgaben wie die Herstellung der Verbindung, die Absicherung gegen Übertragungsfehler, die Aufteilung des anfallenden Datenstroms in Pakete beim Absender und das korrekte Zusammenfügen der Datensegmente beim Empfänger.
Das Ganze hat ja später den Sin das mehrere Dateien zwischen Server und Client transportiert werden können, und das parallel.
Mit der von gandime Beschriebenen Methode vor die Daten eine ID zu hängen, hat ja den Sin das anhand dieser ID beim Server oder Client, das Datenpacket der richtigen Datei (Speicherort) zugeordnet werden kann. Sonst gibt es Datensalat.

Muetze1 26. Jan 2008 19:40

Re: ClientSocket steam verschicken mit vorherigen Zeichen
 
TCP macht dies, ich habe nichts anderes gesagt. Nur die Teilung wird von vielen Nutzern vorausgesetzt, dass sie beim Empfangen genauso ankommen. Mehr wollte ich nicht sagen, der Hinweis war wohl nicht nötig, von daher ignorier es...

d1ng0d0gt0r 26. Jan 2008 19:52

Re: ClientSocket steam verschicken mit vorherigen Zeichen
 
Deine Signatur sagt ja schon alles xD.

Nein ich glaube wir haben einfach aneinander vorbei geredet.

Ich dachte das du meintest, das die Daten wenn sie so abgesendet werden:
SendText('1');
SendText('2');
SendText('3');

auch so ankommen können:
SendText('1');
SendText('3');
SendText('2');

Mein Fehler.

Muetze1 26. Jan 2008 19:58

Re: ClientSocket steam verschicken mit vorherigen Zeichen
 
Nein, viele Leute hier setzen voraus, dass sie das denn auch wieder so empfangen:

Receive('1');
Receive('2');
Receive('3');

aber leider ist es oftmals so:

Receive('12');
Receive('3');

bzw.

Receive('123');

Und dann fallen die Leute aus allen Wolken, weil sie mehr in ihren Code implementieren müssen.

gandime 26. Jan 2008 20:05

Re: ClientSocket steam verschicken mit vorherigen Zeichen
 
ok dann stell dir das Beispiel mal vor du schickst einen Stream mit diesen Vorzeichen 'File-0000' anschliesend der stream als beispeil 'abcd-0000'

also so wird es versendet:
Delphi-Quellcode:
cs.socket.sendtest('File-0000abcd-0000');
jetzt könnte es ja passieren das die daten so bei dem Server ankommen:
Packet 1:
File-0000abc
Packet 2:
d0000

bei Packet 1 wird dann abc als file erkannt und der Datei hinzugefügt, allerdings bei Packet 2 ist es nicht zugewiesen, womit der Server dann nichts anfangen kann

d1ng0d0gt0r 26. Jan 2008 20:08

Re: ClientSocket steam verschicken mit vorherigen Zeichen
 
Genau aus dem Grund würde ich die Daten in so kleinen Schnippseln aus der Datei einlesen und versenden, das eben so etwas nicht passiert.

gandime 26. Jan 2008 20:12

Re: ClientSocket steam verschicken mit vorherigen Zeichen
 
nein guck doch mal die Antwort von Muetze1 an steht wieder eine Möglichkeit drinne!
also du brauchst ein Zeichen oder eine Zeichenfolge die dir sagt: fertig hatte da mal was schönes gecodet:
Delphi-Quellcode:
procedure TForm1.ss_serverClientRead(Sender: TObject; Socket: TCustomWinSocket);
var
  s_receve,s_temp:string;
  b_da:boolean;
  I,i_sockethander: Integer;
begin
  i_sockethander:=socket.SocketHandle;
  for I := 0 to lv_bots.Items.Count - 1 do
  begin
    if (lv_bots.Items.Item[i].SubItems.Strings[8]=inttostr(i_sockethander)) then
    begin
      s_receve:=lv_bots.Items.Item[i].SubItems.Strings[9];
    end;
  end;
  s_receve:=s_receve+Socket.ReceiveText;
  repeat
  begin
    b_da:=false;
    s_temp:='';
    for I := 0 to length(s_receve) -1 do
    begin
      if (s_receve[i]='|') then
      begin
        b_da:=true;
      end;
    end;
    if (b_da=true) then
    begin
      s_temp := copy(s_receve, 1, pos('|', s_receve) - 1);
      s_receve := copy(s_receve, pos('|', s_receve) + 1, length(s_receve));
      for I := 0 to lv_bots.Items.Count - 1 do
      begin
        if (lv_bots.Items.Item[i].SubItems.Strings[8]=inttostr(i_sockethander)) then
        begin
          lv_bots.Items.Item[i].SubItems.Strings[9]:=s_receve;
        end;
      end;
      if (s_temp<>'') then
      begin
        handle(i_sockethander,s_temp);
      end;
    end;
  end;
  until (b_da=false);
end;
damit geht es theoretisch aber du brauchst halt egl zeichen die in einer Datei nicht vorkommen... was aber schwierig wird da ja jedes Zeichen vorkommen kann

Muetze1 26. Jan 2008 20:13

Re: ClientSocket steam verschicken mit vorherigen Zeichen
 
Zitat:

Zitat von d1ng0d0gt0r
Genau aus dem Grund würde ich die Daten in so kleinen Schnippseln aus der Datei einlesen und versenden, das eben so etwas nicht passiert.

Hey, dann war mein Hinweis doch nicht umsonst. Aber genau diese Trennung gibt es nicht, es würde nicht eine Codezeile programmiert um diese Trennung zu übermitteln, weil dazu bräuchte es ein Protokoll und die Komponenten übermitteln aber nur Daten und haben kein Protokoll, weil sonst wären sie nur beschränkt nutzbar.

Somit: Du musst dir selber ein Protokoll ausdenken und entsprechend umsetzen. Wenn du weisst, dass der Anfang immer "File-xxxxx:" ist, dann kannst du im OnClientRead (wenn noch keine Datei empfangen wird), schauen ob im Buffer (Delphi-Referenz durchsuchenSocket.ReceiveLength()) diese Mindestlänge enthalten ist und wenn ja, dann nur diese Anzahl von Zeichen auslesen (im Beispiel hier also 11 Zeichen) und alle nachfolgenden Zeichen sind dann Dateiinhalt.

Das ist dann schon eine Art Protokoll.

/EDIT: roter Kasten???

/EDIT2: gandime: du weisst um direkte Vergleiche mit true bzw. false?

gandime 27. Jan 2008 13:51

Re: ClientSocket steam verschicken mit vorherigen Zeichen
 
Die Procedure von oben ist schon etwas älter und überholt ;-) hatte nich wieder rübergeguckt.
Hab mir jetzt mal eine andere überlegt und zwar werden als erste paar zeichen die Länge des Strings geschickt usw guckt selber ;-)
Delphi-Quellcode:
procedure TForm1.send(s_text:string);
var
  s_length:string;
  i_length:integer;
begin
  i_length:=length(s_text);
  if i_length<10 then
  begin
    s_length:='000'+inttostr(i_length);
  end
  else if i_length<100 then
  begin
    s_length:='00'+inttostr(i_length);
  end
  else if i_length<100 then
  begin
    s_length:='0'+inttostr(i_length);
  end
  else
  begin
    s_length:=inttostr(i_length);
  end;
  cs.Socket.SendText(s_length+s_text);
end;

procedure TForm1.ssClientRead(Sender: TObject; Socket: TCustomWinSocket);
var
  s_receive,s_length,s_command:string;
  i_length:integer;
begin
  if length(s_buff)+socket.ReceiveLength>=4 then
  begin
    s_receive:=s_buff+socket.ReceiveText;
    s_length:=s_Receive;
    setlength(s_length,4);
    i_length:=strtoint(s_length);
    if length(s_receive)-4>=i_length then
    begin
      s_receive:=copy(s_receive,4+1,length(s_receive));
      s_command:=s_receive;
      setlength(s_command,i_length);
      s_buff:=copy(s_receive,i_length+1,length(s_receive));
      //und dann halt auswerten
    end
    else
    begin
      s_buff:=s_receive;
    end;
  end
  else
  begin
    s_buff:=s_buff+socket.ReceiveText;
  end;
end;
jetzt wollte ich fragen ob es zu Komplikationen kommen kann?
wenn z.B. der Server ein falschen Start String bekommt wie finde ich dann den nächsten anfang?


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