Unicode C
Unicode C
HTTP Download in Parallel with Simultaneous Range Requests
See more HTTP Examples
Demonstrates how to download a large file with parallel simultaneous requests, where each request downloads a segment (range) of the remote file.Chilkat Unicode C Downloads
#include <C_CkHttpW.h>
#include <C_CkHttpResponseW.h>
#include <C_CkStringBuilderW.h>
#include <C_CkTaskW.h>
#include <C_CkFileAccessW.h>
void ChilkatSample(void)
{
BOOL success;
HCkHttpW http;
const wchar_t *url;
HCkHttpResponseW resp;
int remoteFileSize;
int chunkSize;
HCkHttpW http1;
HCkHttpW http2;
HCkHttpW http3;
HCkHttpW http4;
HCkStringBuilderW sbRange;
int numReplaced;
HCkTaskW task1;
HCkTaskW task2;
HCkTaskW task3;
HCkTaskW task4;
int numLive;
int numErrors;
HCkFileAccessW fac;
BOOL bSame;
success = FALSE;
// This requires the Chilkat API to have been previously unlocked.
// See Global Unlock Sample for sample code.
http = CkHttpW_Create();
// First get the size of the file to be downloaded.
url = L"https://www.chilkatsoft.com/hamlet.xml";
resp = CkHttpResponseW_Create();
success = CkHttpW_HttpNoBody(http,L"HEAD",url,resp);
if (success == FALSE) {
wprintf(L"%s\n",CkHttpW_lastErrorText(http));
CkHttpW_Dispose(http);
CkHttpResponseW_Dispose(resp);
return;
}
remoteFileSize = CkHttpResponseW_getContentLength(resp);
wprintf(L"Downloading %d bytes...\n",remoteFileSize);
// 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 = CkHttpW_Create();
http2 = CkHttpW_Create();
http3 = CkHttpW_Create();
http4 = CkHttpW_Create();
sbRange = CkStringBuilderW_Create();
CkStringBuilderW_SetString(sbRange,L"bytes=<range-start>-<range-end>");
numReplaced = CkStringBuilderW_ReplaceI(sbRange,L"<range-start>",0);
numReplaced = CkStringBuilderW_ReplaceI(sbRange,L"<range-end>",chunkSize - 1);
wprintf(L"%s\n",CkStringBuilderW_getAsString(sbRange));
CkHttpW_SetRequestHeader(http1,L"Range",CkStringBuilderW_getAsString(sbRange));
CkStringBuilderW_SetString(sbRange,L"bytes=<range-start>-<range-end>");
numReplaced = CkStringBuilderW_ReplaceI(sbRange,L"<range-start>",chunkSize);
numReplaced = CkStringBuilderW_ReplaceI(sbRange,L"<range-end>",2 * chunkSize - 1);
wprintf(L"%s\n",CkStringBuilderW_getAsString(sbRange));
CkHttpW_SetRequestHeader(http2,L"Range",CkStringBuilderW_getAsString(sbRange));
CkStringBuilderW_SetString(sbRange,L"bytes=<range-start>-<range-end>");
numReplaced = CkStringBuilderW_ReplaceI(sbRange,L"<range-start>",2 * chunkSize);
numReplaced = CkStringBuilderW_ReplaceI(sbRange,L"<range-end>",3 * chunkSize - 1);
wprintf(L"%s\n",CkStringBuilderW_getAsString(sbRange));
CkHttpW_SetRequestHeader(http3,L"Range",CkStringBuilderW_getAsString(sbRange));
CkStringBuilderW_SetString(sbRange,L"bytes=<range-start>-");
numReplaced = CkStringBuilderW_ReplaceI(sbRange,L"<range-start>",3 * chunkSize);
wprintf(L"%s\n",CkStringBuilderW_getAsString(sbRange));
CkHttpW_SetRequestHeader(http4,L"Range",CkStringBuilderW_getAsString(sbRange));
// Start each range download
task1 = CkHttpW_DownloadAsync(http1,url,L"qa_output/chunk1.dat");
CkTaskW_Run(task1);
task2 = CkHttpW_DownloadAsync(http2,url,L"qa_output/chunk2.dat");
CkTaskW_Run(task2);
task3 = CkHttpW_DownloadAsync(http3,url,L"qa_output/chunk3.dat");
CkTaskW_Run(task3);
task4 = CkHttpW_DownloadAsync(http4,url,L"qa_output/chunk4.dat");
CkTaskW_Run(task4);
// Wait for the downloads to complete.
numLive = 4;
while (numLive > 0) {
numLive = 0;
if (CkTaskW_getLive(task1) == TRUE) {
numLive = numLive + 1;
}
if (CkTaskW_getLive(task2) == TRUE) {
numLive = numLive + 1;
}
if (CkTaskW_getLive(task3) == TRUE) {
numLive = numLive + 1;
}
if (CkTaskW_getLive(task4) == TRUE) {
numLive = numLive + 1;
}
if (numLive > 0) {
// SleepMs is a convenience method to cause the caller to sleep for N millisec.
// It does not cause the given task to sleep..
CkTaskW_SleepMs(task1,10);
}
}
// All should be downloaded now..
// Examine the result of each Download.
numErrors = 0;
if (CkTaskW_GetResultBool(task1) == FALSE) {
wprintf(L"%s\n",CkTaskW_resultErrorText(task1));
numErrors = numErrors + 1;
}
if (CkTaskW_GetResultBool(task2) == FALSE) {
wprintf(L"%s\n",CkTaskW_resultErrorText(task2));
numErrors = numErrors + 1;
}
if (CkTaskW_GetResultBool(task3) == FALSE) {
wprintf(L"%s\n",CkTaskW_resultErrorText(task3));
numErrors = numErrors + 1;
}
if (CkTaskW_GetResultBool(task4) == FALSE) {
wprintf(L"%s\n",CkTaskW_resultErrorText(task4));
numErrors = numErrors + 1;
}
if (numErrors > 0) {
CkTaskW_Dispose(task1);
CkTaskW_Dispose(task2);
CkTaskW_Dispose(task3);
CkTaskW_Dispose(task4);
CkHttpW_Dispose(http);
CkHttpResponseW_Dispose(resp);
CkHttpW_Dispose(http1);
CkHttpW_Dispose(http2);
CkHttpW_Dispose(http3);
CkHttpW_Dispose(http4);
CkStringBuilderW_Dispose(sbRange);
return;
}
// All downloads were successful.
// Compose the file from the parts.
fac = CkFileAccessW_Create();
success = CkFileAccessW_ReassembleFile(fac,L"qa_output",L"chunk",L"dat",L"qa_output/hamlet.xml");
if (success == FALSE) {
wprintf(L"%s\n",CkFileAccessW_lastErrorText(fac));
}
else {
wprintf(L"Success.\n");
}
CkTaskW_Dispose(task1);
CkTaskW_Dispose(task2);
CkTaskW_Dispose(task3);
CkTaskW_Dispose(task4);
// Let's download in the regular way, and then compare files..
success = CkHttpW_Download(http,url,L"qa_output/hamletRegular.xml");
// Compare files.
bSame = CkFileAccessW_FileContentsEqual(fac,L"qa_output/hamlet.xml",L"qa_output/hamletRegular.xml");
wprintf(L"bSame = %d\n",bSame);
CkHttpW_Dispose(http);
CkHttpResponseW_Dispose(resp);
CkHttpW_Dispose(http1);
CkHttpW_Dispose(http2);
CkHttpW_Dispose(http3);
CkHttpW_Dispose(http4);
CkStringBuilderW_Dispose(sbRange);
CkFileAccessW_Dispose(fac);
}