Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Netzwerke (https://www.delphipraxis.net/14-netzwerke/)
-   -   Delphi BDS2006 Download einer Datei vom Webserver mit TClientSocket (https://www.delphipraxis.net/98655-bds2006-download-einer-datei-vom-webserver-mit-tclientsocket.html)

cramer 30. Aug 2007 15:08


BDS2006 Download einer Datei vom Webserver mit TClientSocket
 
Hallo,
ich lade in meinem Programm mit TClientSocket eine EXE Datei von einem Webserver.
Bei meinen Test unter Windows XP habe ich festgestellt, das vor den Dateidaten im ersten Block der Header (erster Block 268 Byte) vom Webserver mitgeschickt wird.
Zitat:

HTTP/1.1 200 OK Server: Microsoft-IIS/5.0 X-Powered-By: ASP.NET
Date: Thu, 30 Aug 2007 13:20:58 GMT Content-Type: application/octet-stream
Accept-Ranges: bytes Last-Modified: Thu, 30 Aug 2007 08:14:15 GMT
ETag: "80a5ffc0ddeac71:a19" Content-Length: 1446912
Erst im zweiten Block befindet sich der Anfang der Datei. Also habe ich den ersten Block übergangen und speichere die Datei erst ab dem 2. Block. Klappt super, aber wenn ich einen anderen PC mit Windows2000 nehme,
befinden sich schon im ersten Block(4004 Byte) Teile der Datei.
Im ersten Fall unter XP endet der Header mit 2 x CRLF und dann kommen die Daten, im zweiten Fall stehen 3 x CRLF vor den Daten.
Hat jemand eine Idee, wie man Header und Daten sicher trennt und wie sich z.B. ein Apache Webserver als Gegenstelle verhält ?
Thanks in advance

mkinzler 30. Aug 2007 15:11

Re: BDS2006 Download einer Datei vom Webserver mit TClientSo
 
Warum verwendest du keine HTTP-Kompos?

cramer 30. Aug 2007 15:34

Re: BDS2006 Download einer Datei vom Webserver mit TClientSo
 
Habe bei Tests mit den unterschiedlichsten Indy Version unter D5 etliche Hänger, kurioses Verhalten und wenig Abwärtskompatibilität zu älteren Versionen festgestellt und daher wenig Vertrauen dazu.
Im Prinzip klappt es ja auch mit der einfachen SocketVersion, wenn man herausfinden könnte, wie die Trennung Header/Daten funktioniert.
Wenn es gar nicht anders geht, muß ich halt den Header nach der Längenangabe parsen, alle Blöcke speichern und am Ende den Header (EmpfangeneDatenMenge - Headerlängenangabe) vom Anfang der Daten löschen.

Muetze1 30. Aug 2007 15:39

Re: BDS2006 Download einer Datei vom Webserver mit TClientSo
 
1. Du kannst nicht einfach einen Block weglassen weil OnClientRead die Aufrufe teilt. Du kannst dich nicht darauf verlassen - OnClientRead kann beim nächsten Rechner für jedes Zeichen einzelnd aufgerufen werden (übertrieben, aber im Bereich des möglichen) und von daher musst du selber auf die Trennung achten.
2. Wenn keine Indys, dann nutze Windows: InternetOpenURL, InternetDownloadURL, etc.

cramer 30. Aug 2007 15:47

Re: BDS2006 Download einer Datei vom Webserver mit TClientSo
 
OK probiere ich mal aus, InternetOpenUrl habe ich ja gefunden aber ? InternetDownloadURL ?
Gehe ich richtig in der Annahme, daß für die o.g. Funktionen aber auch ein Internetexplorer installiert sein muß
und ClientSocket auch ohne IE funktioniert ?

Muetze1 30. Aug 2007 16:10

Re: BDS2006 Download einer Datei vom Webserver mit TClientSo
 
Ja, aber der IE ist doch standardmässig installiert.

Wenn dich das stört, dann geht die Empfehlung wieder in Richtung Indys...

cramer 30. Aug 2007 16:25

Re: BDS2006 Download einer Datei vom Webserver mit TClientSo
 
Muß er aber nicht bleiben IE Uninstall

cramer 31. Aug 2007 09:03

Re: BDS2006 Download einer Datei vom Webserver mit TClientSo
 
Zur Info, ich habe es jetzt durch Parsen und Auswertung der Content-Length gelöst.
Alle bisherigen Tests auf unterschiedlichen PCs und unter W2K Pro/Server und WXP funktionierten ohne Probleme.
Nachfolgend die Testversion der Procedure.
Delphi-Quellcode:
procedure TForm1.DownloadFile(RemoteHost, RemoteFileName, LocalFileName: string; ClientSocket: TClientSocket);
var
  ReturnCode, Header, LenPos, FileSize, ReadSize : Integer;
  s, tmpStr, LocalFileTemp : string;
  szBuffer : array[0..4095] of Char;
  FileIn  : TFileStream;
  FileOut : TFileStream;
  FileTmp : TFileStream;
begin
  Form1.tag := 0;
  Memo1.Clear;
  Memo2.Clear;
  Memo3.Clear;
  try
    with ClientSocket do begin
      Host := RemoteHost;
      ClientType := ctBlocking;
      Port := 80;
      try
        Open;
        if RemoteFileName[1] <> '/' then begin
           RemoteFileName := '/' + RemoteFileName;
        end;
        { Anfrage senden }
        s := 'GET ' + RemoteFileName + '  HTTP/1.0'#13#10 +
             'Host: ' + Host + #13#10#13#10;
        ReturnCode := Socket.SendBuf(Pointer(s)^, Length(s));
        if ReturnCode > 0 then begin
          { Antwort empfangen }
          header := 0;
          LocalFileTemp := changeFileExt(LocalFileName,'.TMP');
          FileTmp := TFileStream.Create(LocalFileTemp, fmCreate);
          try
            while (ReturnCode > 0) do begin
              FillChar(szBuffer, SizeOf(szBuffer), 0);
              ReturnCode := Socket.ReceiveBuf(szBuffer, SizeOf(szBuffer));
              Memo1.Lines.Add(intToStr(ReturnCode)); // Info Blockgrösse
              if ReturnCode > 0 then begin
                if Header = 0 then begin
                  Header := 1;
                  Memo2.lines.Add(szBuffer);              // Info 1. Block
                  Memo3.lines.Add(szBuffer);              // Info Daten
                  FileTmp.Write(szBuffer, ReturnCode);
                  ReadSize := ReadSize + ReturnCode;
                end else begin
                  Memo3.lines.Add(szBuffer);              // Info Daten
                  FileTmp.Write(szBuffer, ReturnCode);
                  ReadSize := ReadSize + ReturnCode;
                end;
              end;
            end;
          finally
            FileTmp.Free;
          end;
          // Header entfernen
          LenPos := AnsiPos('Content-Length:',Memo2.Text);
          if LenPos > 0 then begin
            tmpStr := trim(copy(Memo3.Text,LenPos,40));
            // Eigene Funktion die einen String/Wert zwischen zwei Trennstrings liefert
            tmpStr := trim(ExtStrT2First('Content-Length:',chr($0D)+chr($0A),tmpStr));
            try
              FileSize := StrToInt(tmpStr);
              FileIn := TFileStream.Create(LocalFileTemp, fmOpenRead);
              try
                FileIn.Seek(ReadSize - FileSize, soFromBeginning);
                ReturnCode := FileIn.Read(szBuffer,4096);
                FileOut := TFileStream.Create(LocalFileName, fmCreate);
                try
                  while ReturnCode > 0 do begin
                    FileOut.Write(szBuffer,ReturnCode);
                    ReturnCode := FileIn.Read(szBuffer,4096);
                  end;
                finally
                  FileOut.Free;
                end;
              finally
                FileIn.Free;
              end;
            except
              Form1.tag := 2003; // Fehler FileSize Auswertung
            end;
            DeleteFile(LocalFileTemp);
          end;
        end else begin
          Form1.tag := 2002;
          Form1.caption := 'Keine Antwort von Server : ' + RemoteHost;
       end;
        Close;
      except
        Form1.tag := 2001;
        Form1.caption := 'Keine Verbindung zum Server : ' + RemoteHost;
      end;
    end;
  finally
    If Form1.Tag < 2000 then Form1.caption := '[' + tmpStr + ']'; // Länge
  end;
end;


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