Tcl
Tcl
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 Tcl Downloads
load ./chilkat.dll
set success 0
# This requires the Chilkat API to have been previously unlocked.
# See Global Unlock Sample for sample code.
set http [new_CkHttp]
# First get the size of the file to be downloaded.
set url "https://www.chilkatsoft.com/hamlet.xml"
set resp [new_CkHttpResponse]
set success [CkHttp_HttpNoBody $http "HEAD" $url $resp]
if {$success == 0} then {
puts [CkHttp_lastErrorText $http]
delete_CkHttp $http
delete_CkHttpResponse $resp
exit
}
set remoteFileSize [CkHttpResponse_get_ContentLength $resp]
puts "Downloading $remoteFileSize bytes..."
# Let's download in 4 chunks.
# (the last chunk will be whatever remains after the 1st 3 equal sized chunks)
set chunkSize [expr $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..
set http1 [new_CkHttp]
set http2 [new_CkHttp]
set http3 [new_CkHttp]
set http4 [new_CkHttp]
set sbRange [new_CkStringBuilder]
CkStringBuilder_SetString $sbRange "bytes=<range-start>-<range-end>"
set numReplaced [CkStringBuilder_ReplaceI $sbRange "<range-start>" 0]
set numReplaced [CkStringBuilder_ReplaceI $sbRange "<range-end>" [expr $chunkSize - 1]]
puts [CkStringBuilder_getAsString $sbRange]
CkHttp_SetRequestHeader $http1 "Range" [CkStringBuilder_getAsString $sbRange]
CkStringBuilder_SetString $sbRange "bytes=<range-start>-<range-end>"
set numReplaced [CkStringBuilder_ReplaceI $sbRange "<range-start>" $chunkSize]
set numReplaced [CkStringBuilder_ReplaceI $sbRange "<range-end>" [expr [expr 2 * $chunkSize] - 1]]
puts [CkStringBuilder_getAsString $sbRange]
CkHttp_SetRequestHeader $http2 "Range" [CkStringBuilder_getAsString $sbRange]
CkStringBuilder_SetString $sbRange "bytes=<range-start>-<range-end>"
set numReplaced [CkStringBuilder_ReplaceI $sbRange "<range-start>" [expr 2 * $chunkSize]]
set numReplaced [CkStringBuilder_ReplaceI $sbRange "<range-end>" [expr [expr 3 * $chunkSize] - 1]]
puts [CkStringBuilder_getAsString $sbRange]
CkHttp_SetRequestHeader $http3 "Range" [CkStringBuilder_getAsString $sbRange]
CkStringBuilder_SetString $sbRange "bytes=<range-start>-"
set numReplaced [CkStringBuilder_ReplaceI $sbRange "<range-start>" [expr 3 * $chunkSize]]
puts [CkStringBuilder_getAsString $sbRange]
CkHttp_SetRequestHeader $http4 "Range" [CkStringBuilder_getAsString $sbRange]
# Start each range download
# task1 is a CkTask
set task1 [CkHttp_DownloadAsync $http1 $url "qa_output/chunk1.dat"]
CkTask_Run $task1
# task2 is a CkTask
set task2 [CkHttp_DownloadAsync $http2 $url "qa_output/chunk2.dat"]
CkTask_Run $task2
# task3 is a CkTask
set task3 [CkHttp_DownloadAsync $http3 $url "qa_output/chunk3.dat"]
CkTask_Run $task3
# task4 is a CkTask
set task4 [CkHttp_DownloadAsync $http4 $url "qa_output/chunk4.dat"]
CkTask_Run $task4
# Wait for the downloads to complete.
set numLive 4
while {$numLive > 0} {
set numLive 0
if {[CkTask_get_Live $task1] == 1} then {
set numLive [expr $numLive + 1]
}
if {[CkTask_get_Live $task2] == 1} then {
set numLive [expr $numLive + 1]
}
if {[CkTask_get_Live $task3] == 1} then {
set numLive [expr $numLive + 1]
}
if {[CkTask_get_Live $task4] == 1} then {
set numLive [expr $numLive + 1]
}
if {$numLive > 0} then {
# 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
}
}
# All should be downloaded now..
# Examine the result of each Download.
set numErrors 0
if {[CkTask_GetResultBool $task1] == 0} then {
puts [CkTask_resultErrorText $task1]
set numErrors [expr $numErrors + 1]
}
if {[CkTask_GetResultBool $task2] == 0} then {
puts [CkTask_resultErrorText $task2]
set numErrors [expr $numErrors + 1]
}
if {[CkTask_GetResultBool $task3] == 0} then {
puts [CkTask_resultErrorText $task3]
set numErrors [expr $numErrors + 1]
}
if {[CkTask_GetResultBool $task4] == 0} then {
puts [CkTask_resultErrorText $task4]
set numErrors [expr $numErrors + 1]
}
if {$numErrors > 0} then {
delete_CkTask $task1
delete_CkTask $task2
delete_CkTask $task3
delete_CkTask $task4
delete_CkHttp $http
delete_CkHttpResponse $resp
delete_CkHttp $http1
delete_CkHttp $http2
delete_CkHttp $http3
delete_CkHttp $http4
delete_CkStringBuilder $sbRange
exit
}
# All downloads were successful.
# Compose the file from the parts.
set fac [new_CkFileAccess]
set success [CkFileAccess_ReassembleFile $fac "qa_output" "chunk" "dat" "qa_output/hamlet.xml"]
if {$success == 0} then {
puts [CkFileAccess_lastErrorText $fac]
} else {
puts "Success."
}
delete_CkTask $task1
delete_CkTask $task2
delete_CkTask $task3
delete_CkTask $task4
# Let's download in the regular way, and then compare files..
set success [CkHttp_Download $http $url "qa_output/hamletRegular.xml"]
# Compare files.
set bSame [CkFileAccess_FileContentsEqual $fac "qa_output/hamlet.xml" "qa_output/hamletRegular.xml"]
puts "bSame = $bSame"
delete_CkHttp $http
delete_CkHttpResponse $resp
delete_CkHttp $http1
delete_CkHttp $http2
delete_CkHttp $http3
delete_CkHttp $http4
delete_CkStringBuilder $sbRange
delete_CkFileAccess $fac