Chilkat HOME .NET Core C# Android™ AutoIt C C# C++ Chilkat2-Python CkPython Classic ASP DataFlex Delphi ActiveX Delphi DLL Go Java Lianja Mono C# Node.js Objective-C PHP ActiveX PHP Extension Perl PowerBuilder PowerShell PureBasic Ruby SQL Server Swift 2 Swift 3,4,5... Tcl Unicode C Unicode C++ VB.NET VBScript Visual Basic 6.0 Visual FoxPro Xojo Plugin
(Delphi DLL) HTTP Download in Parallel with Simultaneous Range RequestsDemonstrates how to download a large file with parallel simultaneous requests, where each request downloads a segment (range) of the remote file.
uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Http, StringBuilder, Task, HttpResponse, FileAccess; ... procedure TForm1.Button1Click(Sender: TObject); var http: HCkHttp; success: Boolean; url: PWideChar; resp: HCkHttpResponse; remoteFileSize: Integer; chunkSize: Integer; http1: HCkHttp; http2: HCkHttp; http3: HCkHttp; http4: HCkHttp; sbRange: HCkStringBuilder; numReplaced: Integer; task1: HCkTask; task2: HCkTask; task3: HCkTask; task4: HCkTask; numLive: Integer; numErrors: Integer; fac: HCkFileAccess; bSame: Boolean; begin // This requires the Chilkat API to have been previously unlocked. // See Global Unlock Sample for sample code. http := CkHttp_Create(); // First get the size of the file to be downloaded. url := 'https://www.chilkatsoft.com/hamlet.xml'; resp := CkHttp_GetHead(http,url); if (CkHttp_getLastMethodSuccess(http) = False) then begin Memo1.Lines.Add(CkHttp__lastErrorText(http)); Exit; end; remoteFileSize := CkHttpResponse_getContentLength(resp); CkHttpResponse_Dispose(resp); Memo1.Lines.Add('Downloading ' + IntToStr(remoteFileSize) + ' bytes...'); // Let's download in 4 chunks. // (the last chunk will be whatever remains after the 1st 3 equal sized chunks) chunkSize := remoteFileSize / 4; // The Range header is used to download a range from a resource // Range: bytes=<range-start>-<range-end> // or // Range: bytes=<range-start>- // We're writing code this way for clarity.. http1 := CkHttp_Create(); http2 := CkHttp_Create(); http3 := CkHttp_Create(); http4 := CkHttp_Create(); sbRange := CkStringBuilder_Create(); CkStringBuilder_SetString(sbRange,'bytes=<range-start>-<range-end>'); numReplaced := CkStringBuilder_ReplaceI(sbRange,'<range-start>',0); numReplaced := CkStringBuilder_ReplaceI(sbRange,'<range-end>',chunkSize - 1); Memo1.Lines.Add(CkStringBuilder__getAsString(sbRange)); CkHttp_SetRequestHeader(http1,'Range',CkStringBuilder__getAsString(sbRange)); CkStringBuilder_SetString(sbRange,'bytes=<range-start>-<range-end>'); numReplaced := CkStringBuilder_ReplaceI(sbRange,'<range-start>',chunkSize); numReplaced := CkStringBuilder_ReplaceI(sbRange,'<range-end>',2 * chunkSize - 1); Memo1.Lines.Add(CkStringBuilder__getAsString(sbRange)); CkHttp_SetRequestHeader(http2,'Range',CkStringBuilder__getAsString(sbRange)); CkStringBuilder_SetString(sbRange,'bytes=<range-start>-<range-end>'); numReplaced := CkStringBuilder_ReplaceI(sbRange,'<range-start>',2 * chunkSize); numReplaced := CkStringBuilder_ReplaceI(sbRange,'<range-end>',3 * chunkSize - 1); Memo1.Lines.Add(CkStringBuilder__getAsString(sbRange)); CkHttp_SetRequestHeader(http3,'Range',CkStringBuilder__getAsString(sbRange)); CkStringBuilder_SetString(sbRange,'bytes=<range-start>-'); numReplaced := CkStringBuilder_ReplaceI(sbRange,'<range-start>',3 * chunkSize); Memo1.Lines.Add(CkStringBuilder__getAsString(sbRange)); CkHttp_SetRequestHeader(http4,'Range',CkStringBuilder__getAsString(sbRange)); // Start each range download task1 := CkHttp_DownloadAsync(http1,url,'qa_output/chunk1.dat'); CkTask_Run(task1); task2 := CkHttp_DownloadAsync(http2,url,'qa_output/chunk2.dat'); CkTask_Run(task2); task3 := CkHttp_DownloadAsync(http3,url,'qa_output/chunk3.dat'); CkTask_Run(task3); task4 := CkHttp_DownloadAsync(http4,url,'qa_output/chunk4.dat'); CkTask_Run(task4); // Wait for the downloads to complete. numLive := 4; while numLive > 0 do begin numLive := 0; if (CkTask_getLive(task1) = True) then begin numLive := numLive + 1; end; if (CkTask_getLive(task2) = True) then begin numLive := numLive + 1; end; if (CkTask_getLive(task3) = True) then begin numLive := numLive + 1; end; if (CkTask_getLive(task4) = True) then begin numLive := numLive + 1; end; if (numLive > 0) then begin // SleepMs is a convenience method to cause the caller to sleep for N millisec. // It does not cause the given task to sleep.. CkTask_SleepMs(task1,10); end; end; // All should be downloaded now.. // Examine the result of each Download. numErrors := 0; if (CkTask_GetResultBool(task1) = False) then begin Memo1.Lines.Add(CkTask__resultErrorText(task1)); numErrors := numErrors + 1; end; if (CkTask_GetResultBool(task2) = False) then begin Memo1.Lines.Add(CkTask__resultErrorText(task2)); numErrors := numErrors + 1; end; if (CkTask_GetResultBool(task3) = False) then begin Memo1.Lines.Add(CkTask__resultErrorText(task3)); numErrors := numErrors + 1; end; if (CkTask_GetResultBool(task4) = False) then begin Memo1.Lines.Add(CkTask__resultErrorText(task4)); numErrors := numErrors + 1; end; if (numErrors > 0) then begin CkTask_Dispose(task1); CkTask_Dispose(task2); CkTask_Dispose(task3); CkTask_Dispose(task4); Exit; end; // All downloads were successful. // Compose the file from the parts. fac := CkFileAccess_Create(); success := CkFileAccess_ReassembleFile(fac,'qa_output','chunk','dat','qa_output/hamlet.xml'); if (success = False) then begin Memo1.Lines.Add(CkFileAccess__lastErrorText(fac)); end else begin Memo1.Lines.Add('Success.'); end; CkTask_Dispose(task1); CkTask_Dispose(task2); CkTask_Dispose(task3); CkTask_Dispose(task4); // Let's download in the regular way, and then compare files.. success := CkHttp_Download(http,url,'qa_output/hamletRegular.xml'); // Compare files. bSame := CkFileAccess_FileContentsEqual(fac,'qa_output/hamlet.xml','qa_output/hamletRegular.xml'); Memo1.Lines.Add('bSame = ' + IntToStr(bSame)); CkHttp_Dispose(http); CkHttp_Dispose(http1); CkHttp_Dispose(http2); CkHttp_Dispose(http3); CkHttp_Dispose(http4); CkStringBuilder_Dispose(sbRange); CkFileAccess_Dispose(fac); end; |
© 2000-2024 Chilkat Software, Inc. All Rights Reserved.