Chinaunix首页 | 论坛 | 博客
  • 博客访问: 335630
  • 博文数量: 100
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 521
  • 用 户 组: 普通用户
  • 注册时间: 2014-10-31 11:37
个人简介

活到老,学到老

文章分类

全部博文(100)

文章存档

2018年(1)

2017年(2)

2016年(11)

2015年(82)

2014年(4)

我的朋友

分类: C/C++

2016-08-14 23:25:28



download.h
  1. #ifndef DOWNLOAD_H
  2. #define DOWNLOAD_H

  3. #include <iostream>
  4. #include <string>
  5. #include <map>
  6. #include <thread>
  7. #include <mutex>
  8. #include <stdio.h>
  9. #include <stdlib.h>


  10. #include <curl/curl.h>

  11. using namespace std;
  12. #ifdef _WIN32
  13.     #include <windows.h>
  14.     #pragma comment(lib,"ws2_32.lib")
  15.     #pragma comment(lib,"winmm.lib")
  16.     #pragma comment(lib,"wldap32.lib")
  17.     #pragma comment(lib,"Advapi32.lib")
  18. #endif

  19. bool download(int threadNum, string url, string path, string fileName);


  20. #endif
download.cpp

  1. #include "download.h"


  2. int currThreadCnt;
  3. int totalThreadNum;
  4. long totalDownloadSize;
  5. bool errorFlag;
  6. map <int, long> downloadMap;
  7. std::mutex m;

  8. struct downloadNode
  9. {
  10.     FILE *fp;
  11.     long startPos;
  12.     long endPos;
  13.     CURL *curl;
  14.     int index;
  15. };

  16. static size_t writeFunc(void *ptr, size_t size, size_t nmemb, void *userdata)
  17. {
  18.     downloadNode *node = (downloadNode *)userdata;
  19.     size_t written = 0;
  20.     m.lock();
  21.     if (node->startPos + size * nmemb <= node->endPos)
  22.     {
  23.         fseek(node->fp, node->startPos, SEEK_SET);
  24.         written = fwrite(ptr, size, nmemb, node->fp);
  25.         node->startPos += size * nmemb;
  26.     }
  27.     else
  28.     {
  29.         fseek(node->fp, node->startPos, SEEK_SET);
  30.         written = fwrite(ptr, 1, node->endPos - node->startPos + 1, node->fp);
  31.         node->startPos = node->endPos;
  32.     }
  33.     m.unlock();
  34.     return written;
  35. }

  36. int progressFunction(void *ptr, double totalToDownload, double nowDownloaded, double totalToUpLoad, double nowUpLoaded)
  37. {
  38.     if (totalToDownload > 0 && nowDownloaded >0)
  39.     {
  40.         m.lock();
  41.         long size = 0L;
  42.         downloadNode *pNode = (downloadNode*)ptr;
  43.         downloadMap[pNode->index] = nowDownloaded;
  44.         map <int, long>::iterator i = downloadMap.begin();
  45.         while (i != downloadMap.end())
  46.         {
  47.             size += i->second;
  48.             ++i;
  49.         }
  50.         size = size - long(totalThreadNum) + 1L;
  51.         //cout <<"currentDownloadSize: "<<size << " tototalSize:"<<totalDownloadSize<<endl;
  52.         m.unlock();
  53.     }
  54.     return 0;
  55. }

  56. long getDownloadFileLenth(const char *url)
  57. {
  58.     double downloadFileLenth = 0;
  59.     CURL *handle = curl_easy_init();
  60.     curl_easy_setopt(handle, CURLOPT_URL, url);
  61.     curl_easy_setopt(handle, CURLOPT_HEADER, 1);
  62.     curl_easy_setopt(handle, CURLOPT_NOBODY, 1);
  63.     if (curl_easy_perform(handle) == CURLE_OK)
  64.     {
  65.         curl_easy_getinfo(handle, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &downloadFileLenth);
  66.     }
  67.     else
  68.     {
  69.         downloadFileLenth = -1;
  70.     }
  71.     return downloadFileLenth;
  72. }

  73. void downloadFinish(FILE *fp)
  74. {
  75.     m.lock();
  76.     currThreadCnt--;
  77.     m.unlock();
  78.     if (currThreadCnt == 0)
  79.     {
  80.         fclose(fp);
  81.         cout << "download succed......" << endl;
  82.     }
  83. }

  84. void downloadError(string errorString)
  85. {
  86.     if (errorFlag)
  87.         return;
  88.     errorFlag = true;
  89.     cout << "download error " << errorString << endl;
  90. }

  91. void *workThread(void *pData)
  92. {
  93.     downloadNode *pNode = (downloadNode *)pData;

  94.     CURLcode curlcode = curl_easy_perform(pNode->curl);
  95.     if (curlcode == CURLE_OK)
  96.     {
  97.         cout << "####thread "<<pNode->index<<"###Downlaod ok" << endl;
  98.         downloadFinish(pNode->fp);
  99.     }
  100.     else
  101.     {
  102.         cout << "####thread " << pNode->index << "#########Downlaod error,Error code:" + curlcode << endl;
  103.         downloadError("Downlaod error, Error code : " + curlcode);
  104.     }
  105.     curl_easy_cleanup(pNode->curl);

  106.     delete pNode;
  107. }


  108. bool download(int threadNum, string url, string path, string fileName)
  109. {
  110.     totalThreadNum = threadNum;
  111.     long fileLength = getDownloadFileLenth(url.c_str());
  112.     if (fileLength <= 0)
  113.     {
  114.         cout<<"get the file length error...";
  115.         return false;
  116.     }
  117.     totalDownloadSize = fileLength;
  118.     cout << ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>totalDownloadsize:" << totalDownloadSize << endl;
  119.     downloadMap.clear();
  120.     errorFlag = false;
  121.     const string outFileName = path + fileName;
  122.     FILE *fp = fopen(outFileName.c_str(), "wb");
  123.     if (!fp)
  124.     {
  125.         return false;
  126.     }

  127.     for (int i = 0; i < threadNum; i++)
  128.     {
  129.         downloadNode *pNode = new downloadNode();
  130.         pNode->startPos = fileLength * i / threadNum;
  131.         pNode->endPos = fileLength * (i + 1) / threadNum;
  132.         CURL *curl = curl_easy_init();

  133.         pNode->curl = curl;
  134.         pNode->fp = fp;
  135.         pNode->index = i + 1;

  136.         char range[64] = { 0 };
  137. #ifdef _WIN32
  138.         _snprintf(range, sizeof (range), "%ld-%ld", pNode->startPos, pNode->endPos);
  139. #else
  140.         snprintf(range, sizeof (range), "%ld-%ld", pNode->startPos, pNode->endPos);
  141. #endif
  142.         curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
  143.         curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writeFunc);
  144.         curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)pNode);
  145.         curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0L);
  146.         curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, progressFunction);
  147.         curl_easy_setopt(curl, CURLOPT_PROGRESSDATA, (void *)pNode);;
  148.         curl_easy_setopt(curl, CURLOPT_RANGE, range);
  149.         curl_easy_setopt(curl, CURLOPT_TIMEOUT, 0L);
  150.         curl_easy_setopt(curl, CURLOPT_FORBID_REUSE, 1L);
  151.         curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);

  152.         m.lock();
  153.         currThreadCnt++;
  154.         m.unlock();
  155.         std::thread thread(workThread, pNode);
  156.         thread.detach();
  157.     }
  158.     while (currThreadCnt > 0)
  159.     {
  160.         Sleep(1000000L);
  161.     }
  162.     return true;

  163. }

阅读(1806) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~