日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 人文社科 > 生活经验 >内容正文

生活经验

libcurl+ncurses 分段range批量下载和进度条显示源码实例

發(fā)布時間:2023/11/27 生活经验 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 libcurl+ncurses 分段range批量下载和进度条显示源码实例 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

這個例子來自參考文獻[1], 那里有很多小bug,我都做了修改,在這里不一一說明了。ncurse界面編程比較容易入門,就是幾個接口,網上資料很多,這里不詳述了。

//gcc -g mget.c -o mget -lcurl -lncurses -lm
//
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <ncurses.h>
#include <time.h>
#include <curl/curl.h>WINDOW *win;
int width, height;WINDOW *create_newwin (int height, int width, int starty, int startx);
void destroy_win (WINDOW * local_win);typedef struct progress
{char byteInterval[64]; //下載分段的字節(jié)范圍int handle; //文件編號或索引double totalDownloaded; //累計下載double segmentSize;//片段總長字節(jié)double currentTime;//當前時間戳double startTime;//開始時間戳
} *dl_progress;size_t write_data (void *ptr, size_t size, size_t nmemb, FILE * stream)
{size_t written;written = fwrite (ptr, size, nmemb, stream);return written;
}static size_t get_size_struct (void *ptr, size_t size, size_t nmemb, void *data)
{(void) ptr;(void) data;// return only the size, dump the restreturn (size_t) (size * nmemb);
}int display_progress (dl_progress pgr)
{int i = pgr->handle;int totalDots = 80; //進度條的長度是80, 剩余的長度是160-80=80double totalDownloaded = pgr->totalDownloaded; //已下載片段大小time_t diffTime = pgr->currentTime - pgr->startTime;double segmentSize = pgr->segmentSize; //總片段大小double averageSpeed = pgr->totalDownloaded / diffTime; //平均下載速度double fractionDownloaded = totalDownloaded / segmentSize; //下載百分比int dots = round (fractionDownloaded * totalDots); //用幾個點來表示?// create the metermvwprintw (win, i + 3, 2, "%3.0f%% [%2d] [", fractionDownloaded * 100, i);int ii = 0;for (; ii < dots; ii++)mvwprintw (win, i + 3, 13 + ii, "="); //8for (; ii < totalDots; ii++)mvwprintw (win, i + 3, 13 + ii, " ");mvwprintw (win, i + 3, totalDots + 13, "]");//注意間隔是40// display some download infomvwprintw (win, i + 3, totalDots + 15, "[%s]", pgr->byteInterval);mvwprintw (win, i + 3, totalDots + 45, "%03.2f KB/s", averageSpeed / 1024);mvwprintw (win, i + 3, width - 18, "%0.2f / %0.2f MB", totalDownloaded / 1024 / 1024, segmentSize / 1024 / 1024);wrefresh (win);return 0;
}int progress_func (dl_progress ptr, double totalToDownload, double nowDownloaded, double totalToUpload, double nowUploaded)
{time_t seconds;seconds = time (NULL);ptr->totalDownloaded = nowDownloaded;ptr->currentTime = seconds;return display_progress (ptr);
}static double get_download_size (char *url)
{CURL *curl;CURLcode res;double size = 0.0;curl = curl_easy_init ();curl_easy_setopt (curl, CURLOPT_URL, url);curl_easy_setopt (curl, CURLOPT_NOBODY, 1L);curl_easy_setopt (curl, CURLOPT_HEADERFUNCTION, get_size_struct);curl_easy_setopt (curl, CURLOPT_FOLLOWLOCATION, 1L);res = curl_easy_perform (curl);res = curl_easy_getinfo (curl, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &size);if (res != CURLE_OK){fprintf (stderr, "curl_easy_getinfo() failed: %s\n", curl_easy_strerror (res));}curl_easy_cleanup (curl);return size;
}int main (int argc, char *argv[])
{if (argc != 3){printf ("Incorrect parameters\nUsage: %s <num_parts> <url>\n", argv[0]);return -1;}// setup the start time for average download speed later when we have finishedtime_t startTime;startTime = time (NULL);// number of partsint parts = strtol (argv[1], &argv[1], 10);	// base 10struct progress *MyProgress = malloc(sizeof(struct progress) * parts);memset(MyProgress, 0 , sizeof(struct progress) * parts);// create the windowinitscr ();height = parts + 5;width = 160; //這里窗口的寬度是160int	starty = (LINES - height) / 2;int startx = (COLS - width) / 2;refresh ();win = create_newwin (height, width, starty, startx);// setup our varsconst char *outputfile;char *url = argv[2];double partSize = 0;double segLocation = 0;int still_running;int i;// get file nameoutputfile = strrchr ((const char *) url, '/') + 1;// get file sizedouble size = get_download_size (argv[2]);partSize = size / parts;mvwprintw (win, 0, 10, "Downloading %dx%0.2f MB segments (%0.2f MB)  %s", parts, size / parts / 1024 / 1024, size / 1024 / 1024, outputfile);// setup curl varsFILE *fileparts[parts];CURL *single_handles[parts];CURLM *multi_handle;CURLMsg *msg;int msgs_left;int error;curl_global_init (CURL_GLOBAL_ALL);for (i = 0; i < parts; i++){time_t seconds;seconds = time (NULL);memset(MyProgress[i].byteInterval, 0, sizeof(MyProgress[i].byteInterval));MyProgress[i].startTime = seconds;MyProgress[i].handle = i;MyProgress[i].segmentSize = partSize;MyProgress[i].totalDownloaded = 0;// setup our output filenamechar filename[50] = { 0 };snprintf (filename, sizeof (filename), "%s.part.%0d", outputfile, i);// allocate curl handle for each segmentsingle_handles[i] = curl_easy_init ();fileparts[i] = fopen (filename, "w");double nextPart = 0;if (i == parts - 1){nextPart = size;}else{nextPart = segLocation + partSize - 1;}char range[64] = { 0 };snprintf (range, sizeof (range), "%12.0f-%12.0f", segLocation, nextPart);memcpy(MyProgress[i].byteInterval, range, strlen(range));// set some curl options.curl_easy_setopt (single_handles[i], CURLOPT_URL, url);curl_easy_setopt (single_handles[i], CURLOPT_RANGE, range);  //設置range請求curl_easy_setopt (single_handles[i], CURLOPT_FOLLOWLOCATION, 1L);curl_easy_setopt (single_handles[i], CURLOPT_WRITEFUNCTION, write_data);//設置接收到文件內容回調curl_easy_setopt (single_handles[i], CURLOPT_WRITEDATA, fileparts[i]); //寫數(shù)據(jù)回調的最后一個參數(shù)curl_easy_setopt (single_handles[i], CURLOPT_NOPROGRESS, 0); //設置進度回調功能curl_easy_setopt (single_handles[i], CURLOPT_PROGRESSFUNCTION, progress_func); //設置進度回調函數(shù)curl_easy_setopt (single_handles[i], CURLOPT_PROGRESSDATA, &MyProgress[i]); //設置進度回調函數(shù)的第一個參數(shù)segLocation += partSize;}multi_handle = curl_multi_init ();// add all individual transfers to the stackfor (i = 0; i < parts; i++){curl_multi_add_handle (multi_handle, single_handles[i]);}curl_multi_perform (multi_handle, &still_running);do{struct timeval timeout;int rc;					// return codefd_set fdread;fd_set fdwrite;fd_set fdexcep;			// file descriptor exceptionint maxfd = -1;long curl_timeo = -1;FD_ZERO (&fdread);FD_ZERO (&fdwrite);FD_ZERO (&fdexcep);// set a suitable timeout to play withtimeout.tv_sec = 100 * 1000;timeout.tv_usec = 0;curl_multi_timeout (multi_handle, &curl_timeo);if (curl_timeo >= 0){timeout.tv_sec = curl_timeo / 1000;if (timeout.tv_sec > 1){timeout.tv_sec = 1;}else{timeout.tv_usec = (curl_timeo % 1000) * 1000;}}curl_multi_fdset (multi_handle, &fdread, &fdwrite, &fdexcep, &maxfd);rc = select (maxfd + 1, &fdread, &fdwrite, &fdexcep, &timeout);switch (rc){case -1:fprintf (stderr, "Could not select the error\n");break;case 0:/* timeout */default:curl_multi_perform (multi_handle, &still_running);break;}}while (still_running);while ((msg = curl_multi_info_read (multi_handle, &msgs_left))){if (msg->msg == CURLMSG_DONE){int index, found = 0;for (index = 0; index < parts; index++){found = (msg->easy_handle == single_handles[index]);if (found)break;}}}// clean up our multi handlecurl_multi_cleanup (multi_handle);// free up the curl handlesfor (i = 0; i < parts; i++){curl_easy_cleanup (single_handles[i]);}// close ncurses windowdestroy_win(win);endwin ();free(MyProgress);// send some output to the console for records sake.time_t endTime;endTime = time (NULL);printf ("Downloaded %0.2f MB in %ld seconds\n", partSize * parts / 1024 / 1024, endTime - startTime);printf ("%0.2f KB/s (average)\n", (partSize * parts / (endTime - startTime) / 1024));return 0;
}WINDOW *create_newwin (int height, int width, int starty, int startx)
{WINDOW *local_win;local_win = newwin (height, width, starty, startx);box (local_win, 0, 0);wrefresh (local_win);return local_win;
}void destroy_win (WINDOW * local_win)
{/* box(local_win, ' ', ' '); : This won't produce the desired* result of erasing the window. It will leave it's four corners* and so an ugly remnant of window.*/wborder (local_win, '|', '|', '-', '-', '+', '+', '+', '+');/* The parameters taken are* 1. win: the window on which to operate* 2. ls: character to be used for the left side of the window* 3. rs: character to be used for the right side of the window* 4. ts: character to be used for the top side of the window* 5. bs: character to be used for the bottom side of the window* 6. tl: character to be used for the top left corner of the window* 7. tr: character to be used for the top right corner of the window* 8. bl: character to be used for the bottom left corner of the window* 9. br: character to be used for the bottom right corner of the window*/wrefresh (local_win);delwin (local_win);
}

運行方法

需要兩個參數(shù),第一個參數(shù)是,分段個數(shù),第二個參數(shù)是大文件的鏈接。默認是大文件下載,上G的文件,可以分為幾十兆一個分段,并行異步下載(注意是單線程異步批量,不是多線程),效果還可以。

./mget 20 "http://cdimage.ubuntu.com/releases/14.04/release/ubuntu-14.04-desktop-amd64+mac.iso"
Downloaded 962.00 MB in 867 seconds
1136.20 KB/s (average)

運行截圖


附加說明

設計UI界面是個費時費力的細致活, 需要根據(jù)屏幕分辨率設計好. 我的ThinkPad是720P的屏,當前的效果給出的是80寬度的框, 進度條使用"="表示, 寬度是40, 高度是文件個數(shù),加上5行空白, 上面是3, 下面是2.一般的筆記本通常沒有高的分辨率,建議框的寬度是40就可以,其他的調整按照參考文獻[1]設置就夠用了。

待解決的問題

如何將這幾個文件的即時速度的和統(tǒng)計出來?我暫時沒有找到較好的方法.希望大牛指點.

參考文獻

[1].https://github.com/logikaljay/mget

總結

以上是生活随笔為你收集整理的libcurl+ncurses 分段range批量下载和进度条显示源码实例的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。