System.Net.httpclient - THTTPClient z XE8

vložil Radek Červinka 19. dubna 2015 23:59

No minule jsem byl k THTTPClient trošku nespravedlivý, ve skutečnosti toho umí více než se zdálo. Kromě https bez nutnosti dodání OpenSSL pro různé platformy to má zajímavé možnosti ohledně paralelního zpracování. Ukáži na malém příkladu.

Ukáži nejprve příklad na zamyšlení a pak vysvětlím co to vlastně dělá.


implementation
uses
  System.Threading,
  System.Net.httpclient;

procedure TForm9.AllocateFile(const sUrl, sFile: string; var iSize: Integer);
var
  oClient: THTTPClient;
  oResponse: IHTTPResponse;
  oFile : TFileStream;
begin
  oClient := THTTPClient.Create;
  try
    if not oClient.CheckDownloadResume(sUrl) then
    begin
      ShowMessage('Not support resume, parallel demo abort, use Get method'); // download direct via oClient.Get
      Abort;
    end;
    oResponse := oClient.Head(sUrl);
    oFile := TFileStream.Create(sFile, fmCreate);
    try
      iSize := oResponse.ContentLength;
      oFile.Size := iSize;
    finally
      oFile.Free;
    end;
  finally
    oClient.Free;
  end;
end;

procedure TForm9.Button1Click(Sender: TObject);
var
  iSize: Integer;
const
  csUrl = 'http://vesta.informatik.rwth-aachen.de/ftp/pub/comp/Linux/knoppix/knoppix-cd/KNOPPIX_V7.2.0bootonly-2013-06-16-EN.iso';
  csFile = 'c:\temp\temp.iso';
  ciSlice = 10;
begin
  AllocateFile(csUrl, csFile, iSize);

  TParallel.&For(0, ciSlice - 1,
     procedure (iIndex: Integer)
     var
       iPartSize, iStart, iEnd: Int64;
       oClient: THTTPClient;
       oFile: TFileStream;
       LResponse: IHTTPResponse;
     begin
       // zjisti jaký blok mám vlastně stahovat
       iPartSize := iSize div ciSlice;
       iStart := iPartSize * iIndex;
       iEnd := iPartSize * (iIndex + 1);
       if iIndex = ciSlice - 1 then  // pro poslední blok malá korekce
         iEnd := iSize;

        oClient := THTTPClient.Create;
        try
          oFile := TFileStream.Create(csFile, fmOpenWrite or fmShareDenyNone);
          try
            oFile.Seek(iStart, soBeginning); // nastav se v souboru na místo
            LResponse := oClient.GetRange(csUrl, iStart, iEnd - 1, oFile); // get it!
          finally
            oFile.Free;
          end;
        finally
          oClient.Free;
        end;
     end
  );
  ShowMessage('Downloaded!');
end;

end.

Kromě THttpClient kód používá možností knihovny System.Threading z XE7: anonymní metodu pouštěnou 10x za pomocí TParallel.For (ten znak & není chyba, ale možnost jak napsat klíčové slovo). Každá instance anonymní metody stáhne svoji část dat do připraveného souboru a celek počká na dokončení všech úloh a pak zahlásí informaci o stažení.

Ano, mohl jsem použít TThread přímo, ale není to takto více čitelnější?

Pro upřesnění: metoda AllocateFile vytvoří na disku prázdný soubor o velikosti budoucího stahovaného souboru. Velikost se získá za pomoci volání THttpClient.Head, kdy se vrací informace o stahovatelných datech. Nejprve se ale zjistí, zda server vůbec podporuje Resume u HTTP (metoda CheckDownloadResume), pokud ne, tak se demo ukončí - na normálním stahování není nic zvláštního.

Samozřejmě si jako vždy rád přečtu Vaše názory v komentářích.

Update: Igor mi napsal o nějakém problému v XE8.1, opraveno v Delphi 10

V XE8 Update 1 je nějaká ptákovina, takže na některých Windows (třeba Windows Server 2008) se ztrácejí parametry u metody GET. Možná by bylo dobré přidat tam komentář, aby si někdo nenabil jako já. Přepsal jsem asi 20 unit, všechno šlapalo jak hodinky, pak to dám na server a konečná. Ztrávil jsem tím několik báječných hodin a na nic jsem nepřišel. Prostě to nechodí. Příslušný server hlásí, že nedostal některé parametry. U mě se to projevilo u GET ve spojení s HTTPS, ale našel jsem report v QC, kde to dalším lidem zlobí zřejmě i na HTTP. Dle toho reportu je tam nějaký bug zanesený v update 1, protože stejný kód jim v XE8 chodil.

quality.embarcadero.com/browse/RSP-11479

Tagy: , , , ,

Novinky v Delphi

Komentáře

20.4.2015 10:51:49 #

z.

Musim se priznat, ze jsem stale skepticky k cele knihovne "System.Net.httpclient", protoze ta knihovna narocnejsi praci s HTTP neumi oproti jiz existujici Indy, ktera zvlada to same (multiplatformni, bez nutnosti OpenSSL).

Navic jsem nedavno cetl o nedostatcich TParallel (problemy s vyuzitim procesoru s vice jak 4 jadry), takze bych si daval pozor na bugy :)

z.

20.4.2015 11:02:03 #

radekc

nedostatcich TParallel
nemáš odkaz?

radekc

20.4.2015 11:15:14 #

radekc

Jedine co jsem nasel je http://stackoverflow.com/questions/29062697/strange-behaviour-of-tparallel-for-default-threadpool
kde se k tomu vyjadruje sam Allan Bauer a podle mne nic zasadniho.

radekc

20.4.2015 12:31:58 #

z.

jj, narazim na toto. Asi to fatalni neni, ale zalezi na konkretnim pripadu, kdy nekdo ocekava, ze to ma nejak fungovat a ono ne. Jen dobre, pokud se to bude rozvijet a zlepsovat. Treba to dosahne moznosti OTL a jeste to bude multiplatformni :)

PS: neni potreba nejak synchronizovat ShowMessage pri provadeni TParallel?

z.

20.4.2015 12:50:43 #

radekc

Jednak tam bylo napsano ze OTL ma reportovano x race condition a leaku a presto je to kvalitni knihovna, druhak ShowMessage je az PO volání TParallel (az se ukončí všechny ukoly).

radekc

Komentování ukončeno

Naše nabídka

MVP
Ing. Radek Červinka - Embarcadero MVP
profil na linkedin, Twitter:@delphicz

Nabízím placené poradenství a konzultace v oblasti programování a vývoje SW.
Dále nabízíme i vývoj speciálního software na zakázku.

Neváhejte nás kontaktovat (i ohledně reklamy).

love Delphi

O Delphi.cz

Delphi je moderní RAD nástroj podporující tvorbu nativních aplikací pro platformu Win32, Win64, Mac OSX, Linux a na iPhone a Android.

Delphi.cz je nezávislý portál pro uživatele Delphi. Portál není koncipován pro úplné začátečníky, i když i ti se zde nebudou nudit, ale spíše na programátory, kteří již něco znají a chtějí své znalosti dále rozvíjet a sledovat novinky.

Poslední komentáře

Comment RSS

Dle měsíců