libcurl使用多线程下载大文件源码示例!
生活随笔
收集整理的這篇文章主要介紹了
libcurl使用多线程下载大文件源码示例!
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
使用libcurl多線程下載大文件的基本思想:
首選打開文件,將文件等分為指定的片段,使用http range下載,一個線程下載一個片段,當線程下載片段時,它們將數據寫到打開文件的指定位置,類似BT文件下載的方式(這樣片段下載完成后不用再合并),當所有的子線程下載完成后,這個大文件也就隨之下載完成了。
下面是相關源碼:
基本上,每個線程都應該有自己的easy handle用于數據通信(如果需要的話)。千萬不要在多線程之間共享同一個easy handle。
待解決的問題:
怎樣通過預生成的線程池來下載呢?
參考文獻
[1].http://blog.csdn.net/zmy12007/article/details/37675331
首選打開文件,將文件等分為指定的片段,使用http range下載,一個線程下載一個片段,當線程下載片段時,它們將數據寫到打開文件的指定位置,類似BT文件下載的方式(這樣片段下載完成后不用再合并),當所有的子線程下載完成后,這個大文件也就隨之下載完成了。
下面是相關源碼:
//g++ -g curl_multithread_demo1.cpp -o curl_multithread_demo1 -lcurl -lpthread
//./curl_multithread_demo1
//說明: 該程序使用指定的線程數N來下載一個大文件,將該大文件等分為N+1個分片,每個線程一個分片, 使用range請求.下載完成,子線程退出, 線程數減一
//主線程等到所有的子線程都退出后, 意味著文件下載完成,就關閉文件等待退出.每個線程下載的數據存放在文件的指定位置, 1個master線程, N+1個work線程
//為啥使用互斥鎖?因為它包含線程的計數, 文件的寫入.這里對文件的讀寫比較贊, 雖然是分開下載,但是對文件沒有單獨存放,省去了最后的合并過程.
//#include <iostream>
#include <string>
#include <unistd.h>
#include <pthread.h>
#include <curl/curl.h>using namespace std;struct tNode
{FILE *fp;long startPos;long endPos;void *curl;pthread_t tid;
};int threadCnt = 0;
static pthread_mutex_t g_mutex = PTHREAD_MUTEX_INITIALIZER;static size_t writeFunc (void *ptr, size_t size, size_t nmemb, void *userdata)
{tNode *node = (tNode *) userdata;size_t written = 0;pthread_mutex_lock (&g_mutex);if (node->startPos + size * nmemb <= node->endPos){fseek (node->fp, node->startPos, SEEK_SET);written = fwrite (ptr, size, nmemb, node->fp);node->startPos += size * nmemb;}else{fseek (node->fp, node->startPos, SEEK_SET);written = fwrite (ptr, 1, node->endPos - node->startPos + 1, node->fp);node->startPos = node->endPos;}pthread_mutex_unlock (&g_mutex);return written;
}int progressFunc (void *ptr, double totalToDownload, double nowDownloaded, double totalToUpLoad, double nowUpLoaded)
{int percent = 0;if (totalToDownload > 0){percent = (int) (nowDownloaded / totalToDownload * 100);}if(percent % 20 == 0)printf ("下載進度%0d%%\n", percent);return 0;
}/************************************************************************/
/* 獲取要下載的遠程文件的大小 */
/************************************************************************/
long getDownloadFileLenth (const char *url)
{double downloadFileLenth = 0;CURL *handle = curl_easy_init ();curl_easy_setopt (handle, CURLOPT_URL, url);curl_easy_setopt (handle, CURLOPT_HEADER, 1); //只需要header頭curl_easy_setopt (handle, CURLOPT_NOBODY, 1); //不需要bodyif (curl_easy_perform (handle) == CURLE_OK){curl_easy_getinfo (handle, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &downloadFileLenth);}else{downloadFileLenth = -1;}return downloadFileLenth;
}void *workThread (void *pData)
{tNode *pNode = (tNode *) pData;int res = curl_easy_perform (pNode->curl);if (res != 0){}curl_easy_cleanup (pNode->curl);pthread_mutex_lock (&g_mutex);threadCnt--;printf ("thred %ld exit\n", pNode->tid);pthread_mutex_unlock (&g_mutex);delete pNode;pthread_exit (0);return NULL;
}bool downLoad (int threadNum, string Url, string Path, string fileName)
{long fileLength = getDownloadFileLenth (Url.c_str ());if (fileLength <= 0){printf ("get the file length error...");return false;}// Create a file to save package.const string outFileName = Path + fileName;FILE *fp = fopen (outFileName.c_str (), "wb");if (!fp){return false;}long partSize = fileLength / threadNum;for (int i = 0; i <= threadNum; i++){tNode *pNode = new tNode ();if (i < threadNum){pNode->startPos = i * partSize;pNode->endPos = (i + 1) * partSize - 1;}else{if (fileLength % threadNum != 0){pNode->startPos = i * partSize;pNode->endPos = fileLength - 1;}elsebreak;}CURL *curl = curl_easy_init ();pNode->curl = curl;pNode->fp = fp;char range[64] = { 0 };snprintf (range, sizeof (range), "%ld-%ld", pNode->startPos, pNode->endPos);// Download pacakgecurl_easy_setopt (curl, CURLOPT_URL, Url.c_str ());curl_easy_setopt (curl, CURLOPT_WRITEFUNCTION, writeFunc);curl_easy_setopt (curl, CURLOPT_WRITEDATA, (void *) pNode);curl_easy_setopt (curl, CURLOPT_NOPROGRESS, 0L);curl_easy_setopt (curl, CURLOPT_PROGRESSFUNCTION, progressFunc);curl_easy_setopt (curl, CURLOPT_NOSIGNAL, 1L);curl_easy_setopt (curl, CURLOPT_LOW_SPEED_LIMIT, 1L);curl_easy_setopt (curl, CURLOPT_LOW_SPEED_TIME, 5L);curl_easy_setopt (curl, CURLOPT_RANGE, range);pthread_mutex_lock (&g_mutex);threadCnt++;pthread_mutex_unlock (&g_mutex);int rc = pthread_create (&pNode->tid, NULL, workThread, pNode);}while (threadCnt > 0){usleep (1000000L);}fclose (fp);printf ("download succed......\n");return true;
}int main (int argc, char *argv[])
{
// downLoad (10,
// "http://101.26.37.79/ws.cdn.baidupcs.com/file/2c72878c8a5731a27f6d0a6018173520?xcode=ccef659b8500cc28f5ca86d0cbb8d4c6e6c008630559e8680b2977702d3e6764&fid=335809860-250528-463118344000947&time=1410621706&sign=FDTAXER-DCb740ccc5511e5e8fedcff06b081203-zXbBKRSs5knf%2BKll6uykeWpQoTY%3D&to=cb&fm=Nin,B,U,nc&sta_dx=105&sta_cs=98&sta_ft=mp4&sta_ct=3&newver=1&newfm=1&flow_ver=3&expires=8h&rt=pr&r=487142437&mlogid=3863405498&vuk=335809860&vbdid=140272377&fn=opclass.com-%E4%BA%92%E8%81%94%E7%BD%91%E6%97%B6%E4%BB%A3%E7%AC%AC1%E9%9B%86%EF%BC%9A%E6%97%B6%E4%BB%A3.mp4&wshc_tag=0&wsts_tag=5414610a&wsid_tag=72f52ad0&wsiphost=ipdbm",
// "./", "Network_Age_1.mp4");downLoad (10,"http://139.209.90.30/ws.cdn.baidupcs.com/file/03f85133cb241c57cc17f5baf66b9820?xcode=e38bc1881ff679abc91893c2710fc81ac7f100988f506460837047dfb5e85c39&fid=335809860-250528-571147930138020&time=1410622082&sign=FDTAXER-DCb740ccc5511e5e8fedcff06b081203-cJtuWcK6QQghdq9RC%2F%2F4eJQ39gU%3D&to=cb&fm=Nin,B,U,nc&sta_dx=105&sta_cs=89&sta_ft=mp4&sta_ct=3&newver=1&newfm=1&flow_ver=3&expires=8h&rt=pr&r=588575374&mlogid=1816906087&vuk=335809860&vbdid=140272377&fn=opclass.com-%E4%BA%92%E8%81%94%E7%BD%91%E6%97%B6%E4%BB%A3%E7%AC%AC2%E9%9B%86%EF%BC%9A%E6%B5%AA%E6%BD%AE.mp4&wshc_tag=0&wsts_tag=54146282&wsid_tag=72f52ad0&wsiphost=ipdbm","./", "Network_Age_2.mp4");
// downLoad (10,
// "http://121.18.230.69/ws.cdn.baidupcs.com/file/e2b36423e8f1cc4019d77598e32870f5?xcode=d60f60ab1a1746111db642272c0f9726fcfce98aadfaf01d0b2977702d3e6764&fid=335809860-250528-544759395965909&time=1410617631&sign=FDTAXER-DCb740ccc5511e5e8fedcff06b081203-eirgEMQqOKx5ssfzMt%2Ft0JEbvM0%3D&to=cb&fm=Nin,B,U,nc&sta_dx=173&sta_cs=74&sta_ft=mp4&sta_ct=3&newver=1&newfm=1&flow_ver=3&expires=8h&rt=pr&r=943427300&mlogid=3977494833&vuk=335809860&vbdid=140272377&fn=opclass.com-%E4%BA%92%E8%81%94%E7%BD%91%E6%97%B6%E4%BB%A3%E7%AC%AC10%E9%9B%86%EF%BC%9A%E7%9C%BA%E6%9C%9B.mp4&wshc_tag=0&wsts_tag=54145120&wsid_tag=72f52ad0&wsiphost=ipdbm",
// "./", "Network_Age_10.mp4");//downLoad(10, "http://ardownload.adobe.com/pub/adobe/reader/win/11.x/11.0.01/en_US/AdbeRdr11001_en_US.exe", "./", "AdbeRdr11001_en_US.exe");getchar ();return 0;
}
使用方法:
在main函數中, 指定要下載的線程數, 下載大文件的url, 存放在本地的文件目錄(末尾需要加/), 待存放的文件名, 這幾個都寫死在代碼, 然后編譯并運行
g++ -g curl_multithread_demo1.cpp -o curl_multithread_demo1 -lcurl -lpthread
./curl_multithread_demo1
下載后的文件目錄
文件完整性驗證:
為了驗證代碼的準確性,我選用百度云盤上的視頻文件《互聯網時代》紀錄片來進行下載,下載完成后,我使用vlc播放器來播放,發現播放是正常的,這說明程序沒有問題。
我們也可以下載Ubuntu 14.04.1官網的iso,下載完成后,使用md5check來檢查下載文件的md5值與官網提供的是否相同。
要注意的問題基本上,每個線程都應該有自己的easy handle用于數據通信(如果需要的話)。千萬不要在多線程之間共享同一個easy handle。
待解決的問題:
怎樣通過預生成的線程池來下載呢?
參考文獻
[1].http://blog.csdn.net/zmy12007/article/details/37675331
總結
以上是生活随笔為你收集整理的libcurl使用多线程下载大文件源码示例!的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: libcurl+ncurses 分段ra
- 下一篇: vim中的转义符