Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Netzwerke (https://www.delphipraxis.net/14-netzwerke/)
-   -   Delphi (Indy) TCPClient bekommt zuviel vom Server (https://www.delphipraxis.net/67843-indy-tcpclient-bekommt-zuviel-vom-server.html)

Harry M. 20. Apr 2006 18:08


(Indy) TCPClient bekommt zuviel vom Server
 
Mahlzeit!

Ich möchte mit einem Indy TCPClient von einem Indy TCPServer eine Datei holen (was auch sonst :lol: ) Der Server sendet dabei (im Debugg-Modus) einen 2048 Byte grossen Stream an den Client dieser empfängt aber gleich mehr als die ganz Datei :pale:

Der Client;
Delphi-Quellcode:
procedure TDownloadThread.DownloadFile;
begin
  TCPClient := TIdTCPClient.Create(nil);
  TCPClient.Host := sHost;
  TCPClient.Port := iPort;

  try
    TCPClient.Connect(-1);
    except end;

  if TCPClient.Connected then begin
    TCPClient.WriteLn('GETSIZE='+sFileName);

    iRemoteFileSize := StrToInt(TCPClient.ReadLn);

    if iRemoteFileSize > 0 then begin
      TCPClient.WriteLn('GETFILE='+sFileName);

      fs := TFileStream.Create(sFileName + '.copy' ,fmCreate);
      ms := TMemoryStream.Create;

      sStatus := StatusWork;
      sProgress := IntToStr( Round(fs.Size/iRemoteFileSize*100) ) + '%';
      Synchronize(SyncProgress);

      while (TCPClient.Connected) and (fs.Size < iRemoteFileSize) do begin
       ms.Clear;

       try
        TCPClient.ReadStream(ms); // hier sollte er immer nur 2048 bzw den Rest bekommen, tut er aber nicht :-(
        except end;

        if ms.Size > 0 then
          fs.CopyFrom(ms, 0);

        sProgress := IntToStr( Round(fs.Size/iRemoteFileSize*100) ) + '%';
        Synchronize(SyncProgress);
        end;

      FreeAndNil(fs);
      FreeAndNil(ms);
      end;

    end;

  sStatus := StatusDone;
  Synchronize(SyncProgress);
  TCPClient.Free;
end;
Der Server, welcher meiner Meinug nach läuft:
Delphi-Quellcode:
procedure TVPumper.IdTCPServer1Execute(AThread: TIdPeerThread);
var
  fs: TFileStream;
  ms: TMemoryStream;
  I: Integer;
  iBytes2Send: Cardinal;
  S, sCommand, sFileName, sHash: String;
  slFileList: TStringList;
begin
  S := UpperCase(AThread.Connection.ReadLn);

  slFileList := TStringList.Create;

  sCommand := Copy(S, 1, 7);
  sFileName := Copy(S, 9, Length(S));

  // Dateiliste erstellen
  if sCommand = 'GETLIST' then begin
    if CreateFileList(ShreadFolder + '*.*', sFileName, slFileList) then
      slFileList.Text := StringReplace(slFileList.Text, '', '', [rfReplaceAll]);
      AThread.Connection.WriteLn(slFileList.Text);
      AThread.Connection.Disconnect;
    end;
                       
  if sCommand = 'GETSIZE' then begin

    sHash := Copy(S, 9, Length(S));

    if CreateFileList(ShreadFolder + '*.*', sHash, slFileList) then begin
      I := Pos('|', slFileList.Text) + 1;
      slFileList.Text := Copy(slFileList.Text, I, Length(slFileList.Text));

      I := Pos('|', slFileList.Text) - 1;
      slFileList.Text := Copy(slFileList.Text, 1, I);

      AThread.Connection.WriteLn(slFileList.Text);
      //AThread.Connection.Disconnect;
      end;

    end;

  if sCommand = 'GETFILE' then begin
    sHash := Copy(S, 9, Length(S));
    sFileName := Hash2File(sHash);

    fs := TFileStream.Create(sFileName ,fmOpenRead   + fmShareDenyNone);
    ms := TMemoryStream.Create;

    while fs.Position < fs.Size do begin
      ms.Clear;

      iBytes2Send := fs.Size - fs.Position;

      if iBytes2Send > 2048 then
        iBytes2Send := 2048;

      ms.CopyFrom(fs, iBytes2Send);

      AThread.Connection.OpenWriteBuffer;
      AThread.Connection.WriteStream(ms, True, True); // immer fleißig 2048 schauffeln, bzw den Rest
      AThread.Connection.CloseWriteBuffer;

      end;

    AThread.Connection.Disconnect;
    FreeAndNil(fs);
    FreeAndNil(ms);
    end;

  slFileList.Free;
end;
Wo liegt der Fehler (ausser im Detail :lol: ) ?

marabu 20. Apr 2006 18:34

Re: (Indy) TCPClient bekommt zuviel vom Server
 
Hallo Harry,

ich glaube der Fehler liegt im Konzept - ohne ein handshaking protocol schickt der Server alles auf einmal, auch wenn du den send buffer immer erst bei einer water mark von 2048 frei gibst.

Grüße vom marabu

Harry M. 20. Apr 2006 18:37

Re: (Indy) TCPClient bekommt zuviel vom Server
 
Liste der Anhänge anzeigen (Anzahl: 1)
Hallo Marabu!

Im Demo Projekt, welches ich mir zum besseren Verständnis des Problems gemacht habe (s. Anhang) geht alles einwandfrei. Basiert auf der gleichen Technik.

marabu 20. Apr 2006 21:37

Re: (Indy) TCPClient bekommt zuviel vom Server
 
Deine Demo läuft bei mir in deutlich sichtbaren Schritten, aber warum? Meine TEST.DAT hat 466 KByte. Nach dem Studium der Dokumentation bin ich leicht irritiert. Die SendBufferSize ist 32 KByte per default. Deine Akrobatik mit 2048 ist relativ nutzlos, wenn ich der Online-Hilfe glauben darf. Wie hast du getestet? Protokolliere mal bei jedem ReadStream die Anzahl der empfangenen Bytes. Dateien mit maximal 32 KByte müssten in einem Rutsch übertragen werden. Ist dir bewusst, dass deine GETFILESIZE-Mimik das ohnehin schon verwendete Protokoll doppelt?

marabu

Harry M. 21. Apr 2006 03:30

Re: (Indy) TCPClient bekommt zuviel vom Server
 
Hey marabu,

Das Problem habe ich wiefolgt gelöst:

Server:
Delphi-Quellcode:
AThread.Connection.WriteLn(Trim (slFileList.Text) );
// Hier flog am Ende ein #13 mit durch was beim ersten Empfang des Steam-Buffers mit übertragen wurde. Deshalb war die File am Ende immer grösser.
Danke Deiner Mühen.


Alle Zeitangaben in WEZ +1. Es ist jetzt 00:59 Uhr.

Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz