libcurl 编程进度条和range请求源码示例

时间:2022-02-15 16:43:44

在下面的源码中,我将展示如何使用libcurl提供的进度条功能,以及如何发送range请求, 同时提供了限速功能。

源码如下:

//g++ -g curl_range.cpp -o curl_range -lcurl -lm
//
#include <iostream>
#include <string>
#include <math.h>
#include <curl/curl.h>

using namespace std;

int progress_func(void* ptr, double TotalToDownload, double NowDownloaded, double TotalToUpload, double NowUpload)
{
//how wide you want the progress bar to be ?
int totalDot = 80;

double fractionDownloaded = 0.0;
if(TotalToDownload != 0)
fractionDownloaded = NowDownloaded / TotalToDownload;//注意0不能为分母
else
fractionDownloaded = 0;
//the full part of progress bar
int dot = round(fractionDownloaded * totalDot);

//create the progress bar, but control to print
if(dot % 10 == 0){
printf("total: %0.0f, now: %0.0f\n", TotalToDownload, NowDownloaded);
int i = 0;
printf("%3.0f%% [", fractionDownloaded * 100);
for(; i < dot; i++)
printf("="); // full part
for(; i < totalDot; i++)
printf(" "); // remainder part
printf("]\n");
fflush(stdout); //avoid output buffering problems
}

return 0;
}

int download (string url, string local_file, int down_speed)
{
CURL *curl;
CURLcode res;
FILE *fp;

curl = curl_easy_init ();
if (curl)
{
//Open File
fp = fopen (local_file.c_str (), "w");
if (fp == NULL)
cout << "File cannot be opened" << endl;

curl_easy_setopt (curl, CURLOPT_URL, url.c_str ());
curl_easy_setopt (curl, CURLOPT_FOLLOWLOCATION, 1);
//这里限速 XX KB/s
curl_easy_setopt (curl, CURLOPT_MAX_RECV_SPEED_LARGE, (curl_off_t) down_speed * 1024);
curl_easy_setopt (curl, CURLOPT_RANGE, "0-100000000"); //设置range请求, 只下载前100MB
// curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
curl_easy_setopt (curl, CURLOPT_WRITEFUNCTION, NULL);
curl_easy_setopt (curl, CURLOPT_WRITEDATA, fp);
curl_easy_setopt (curl, CURLOPT_NOPROGRESS, 0);
//禁用内部CURL进度显示条,假如我们提供了自定义的
curl_easy_setopt (curl, CURLOPT_PROGRESSFUNCTION, progress_func);

//限速下载
res = curl_easy_perform (curl);
if (res)
cout << "Cannot grab the File!\n";
}
//Clean up the resources
curl_easy_cleanup (curl);
//Close the file
fclose (fp);
return 0;
}

int main (int argc, char *argv[])
{
string url ("http://cdimage.ubuntu.com/releases/14.04/release/ubuntu-14.04-desktop-amd64+mac.iso");
string filepath ("./a.iso");
int downspeed = 600;

int ret = download (url, filepath, downspeed);
cout << "download [result]: " << ret << endl;

return 0;
}

下载过程中,和下载完成时的运行截图:

libcurl 编程进度条和range请求源码示例

libcurl 编程进度条和range请求源码示例

几个知识点强调:

CURLcode curl_easy_setopt(CURL *handle, CURLoption option, parameter);  
      1. 设置下载数据的回调函数.      
     option:      
     CURLOPT_WRITEFUNCTION //设置回调函数,这个必须得有,否则libcurl的下载数据将直接显示在终端
         回调函数原型为: size_t function( void *ptr, size_t size, size_t nmemb, void *userp); 必须返回数据长度, 函数将在libcurl接收到数据后被调用。
         void *ptr是下载回来的数据.
         void *userp是用户指针, 用户通过这个指针传输自己的数据.
     CURLOPT_WRITEDATA 
      设置回调函数中的void *userp指针的来源。
      2. 下载进度控制.
     option:
     CURLOPT_NOPROGRESS  
       为了使CURLOPT_PROGRESSFUNCTION被调用. CURLOPT_NOPROGRESS必须被设置为false.如果没有下面的进度函数,将使用默认的进度条展示在终端
     CURLOPT_PROGRESSFUNCTION
       CURLOPT_PROGRESSFUNCTION 指定的函数正常情况下每秒被libcurl调用一次.
     CURLOPT_PROGRESSDATA
       CURLOPT_PROGRESSDATA指定的参数将作为CURLOPT_PROGRESSFUNCTION指定函数的参数. 
     整个处理与下载数据回调的处理相同. 
     3. 其它常用属性. 
     option:
     CURLOPT_URL
       设置访问的URI.
     CURLOPT_NOSIGNAL
       屏蔽其它信号.
     CURLOPT_HEADER
       取数据时连同HTTP头部一起取回.
     CURLOPT_HEADERFUNCTION
     CURLOPT_HEADERDATA
       只取HTTP头部数据, 处理与下载数据回调的处理相同. 
     CURLOPT_TIMEOUT
       超时时间.
     CURLOPT_CONNECTIONTIMEOUT
       连接等待时间.
     CURLOPT_FOLLOWLOCATION
     设置支持302重定向
     CURLOPT_RANGE
      断点续传, 指定传输分片, 格式:"0-200", 在上面源码的进度条函数中,我们可以看到设置range中,我们得到的TotalToDownload只是一个该分片的长度,而非整个文件的长度, 同时NowDownloaded会每秒刷新, 长度不断增大, 最后直至达到该分片的长度.

参考文献:

[1].http://blog.chinaunix.net/uid-20692625-id-3203258.html