coco2dx c++ 断点续传实现



coco2dx c++ 断点续传实现

实现效果如下

iPhone截图

android 日志截图

流程图如下

功能主要通过CURL c pthread 实现 我实现的不是多线程断点(如果要实现可以根据我这个进行添加任务序列,可参考 cocos2d-x 中AssetsManager的实现,其实我的部分也是参考这个写的 为什么写这个呢 原因就是 AssetsManager是不支持断点续传的)

博客地址:http://blog.csdn.net/vpingchangxin/article/details/22309067

具体可以去CURL官网或者找资料科普一下

PS:如果是版本发布最后设置超时时间20秒左右否则下载会占用更多下载实现效率等问题 我是为了测试 设置超时时间为2秒

1.先创建一个界面进行控制进行下载、停止、删除、进度 并绑定事件

2.在进行下载中开一个线程进行下载 (因为牵涉到UI,不开线程UI会卡着堵塞UI线程直到下载完成)下面是事件中的控制 HelloWorldSecene.cpp中的实现

 

  1. void HelloWorld::menuCallback(CCObject* pSender) {
  2.     CCMenuItem *item = (CCMenuItem *)pSender;
  3.     switch (item->getTag()) {
  4.         case 1: // down start
  5.             CCDirector::sharedDirector()->getScheduler()->scheduleSelector(schedule_selector(HelloWorld::updateUI), this, 0, false); // HttpClient中参考
  6.             isStop = false;
  7.             this->threadStart();
  8.             break;
  9.         case 2: // down stop
  10.             isStop = true;
  11.             break;
  12.         case 3:
  13.             if (isStop) {
  14.                 CCLog(“downFilePath:%s”,downFilePath.c_str());
  15.                 if (access(downFilePath.c_str(), 0) == 0) {
  16.                     remove(downFilePath.c_str());
  17.                     CCMessageBox(“删除成功”, ”温馨提示”);
  18.                 }else{
  19.                     CCMessageBox(“没有找到文件目录”, ”温馨提示”);
  20.                 }
  21.             }else{
  22.                 CCMessageBox(“下载中或没有文件下载”, ”温馨提示”);
  23.             }
  24.             break;
  25.         default:
  26.             break;
  27.     }
  28. }

3。实现线程类并回调设置

 

  1. // 启动线程的方法
  2. int HelloWorld::threadStart() {
  3.     pthread_mutex_init(&g_downloadMutex, NULL);
  4.     int errCode=0;
  5.     pthread_t th_curlDown; // 线程初始化
  6.     do {
  7.         pthread_attr_t tAttr;
  8.         errCode=pthread_attr_init(&tAttr);
  9.         CC_BREAK_IF(errCode!=0);
  10.         errCode=pthread_attr_setdetachstate(&tAttr, PTHREAD_CREATE_DETACHED);
  11.         if(errCode!=0) {
  12.             pthread_attr_destroy(&tAttr);
  13.             break;
  14.         }
  15.         errCode=pthread_create(&th_curlDown, &tAttr, thread_funcation, this);
  16.     } while (0);
  17.     return errCode;
  18. }
  19. // 需要线程来完成的功能都写在这个函数里
  20. void* HelloWorld::thread_funcation(void *arg) {
  21.     CCLOG(“thread started…”);
  22.     HelloWorld *hw = (HelloWorld*)arg;
  23.     hw->ccc = new CurlDown(“http://developer.baidu.com/map/static/doc/output/BaiduMap_AndroidSDK_v2.4.0_All.zip”,hw->downFilePath);
  24.     //    ccc->mDownloadUrl = ”http://developer.baidu.com/map/static/doc/output/BaiduMap_AndroidSDK_v2.4.0_All.zip”;
  25.     //    int leng = ccc->getDownloadFileLenth();
  26.     hw->ccc->setDelegate(hw);
  27.     hw->ccc->downloadControler();
  28.     return NULL;
  29. }

4.实现回调进度、成功、错误(里面用到线程锁对数据进度更新UI,本来对线程就不熟悉,问了群里面的大牛,看了不少资料)


 

 

  1. void HelloWorld::onError(CurlDown::ErrorCode errorCode){
  2.     CCLog(“error”);
  3.     pthread_mutex_lock(&g_downloadMutex);
  4.     updateStr = ”error”;
  5.     pthread_mutex_unlock(&g_downloadMutex);
  6.     CCDirector::sharedDirector()->getScheduler()->unscheduleSelector(schedule_selector(HelloWorld::updateUI), this);
  7. }
  8. void HelloWorld::onProgress(double percent, void *delegate, string filefullPath){ // 下载进度
  9.     CCLog(“donw progress:%.2f%%”,percent);
  10.     if (isStop) {
  11.         CurlDown * cd = (CurlDown *)delegate;
  12.         //        pthread_mutex_lock(&g_downloadMutex);
  13.         cd->setStopDown();
  14.         //        pthread_mutex_unlock(&g_downloadMutex);
  15.     }
  16.     pthread_mutex_lock(&g_downloadMutex);
  17.     const char * per =CCString::createWithFormat(“donw progress:%.2f%%”,percent)->getCString();
  18.     updateStr = per;
  19.     downFilePath = filefullPath;
  20.     pthread_mutex_unlock(&g_downloadMutex);
  21. }
  22. void HelloWorld::onSuccess(string filefullPath){
  23.     CCLog(“success”);
  24.     pthread_mutex_lock(&g_downloadMutex);
  25.     updateStr = ”success”;
  26.     downFilePath = filefullPath;
  27.     pthread_mutex_unlock(&g_downloadMutex);
  28. }

5.CurlDown.h CurlDown.cpp类实现 (可以直接抽取出来用于任何地方,没有牵涉到cocos2d-x部分,cocos2d-x 部分可以删除没关系)

 

1)对类初始化

 

  1. static pthread_mutex_t g_downloadMutex_1;
  2. CurlDown::~CurlDown(){
  3.     mFileLenth = 0;
  4. }
  5. CurlDown::CurlDown():isStop(false),mDownloadUrl(“”),timeout(2){ // test timeout 2 seconds. if release timeout 20 seconds
  6.     mFileLenth = 0;
  7.     mFilePath = ”";
  8.     pthread_mutex_init(&g_downloadMutex_1, NULL);
  9. }
  10. CurlDown::CurlDown(string downUrl,string filePath):mFileLenth(0),isStop(false),mDownloadUrl(downUrl),timeout(2),mFilePath(filePath){  // test timeout 2 seconds. if release timeout 20 seconds
  11.     mDownloadUrl = downUrl;
  12.     pthread_mutex_init(&g_downloadMutex_1, NULL);
  13. }
  14. void CurlDown::setDelegate(CurlDownDelegate * delegate) {
  15.     mDelegate = delegate;
  16. }

2)控制下载方法

 

 

  1. void CurlDown::downloadControler() {
  2.     CCLog(“–1-”);
  3.     mFileLenth = getDownloadFileLenth(); // 获取远程文件大小
  4.     if (mFileLenth <= 0) {
  5.         cout << ”download file fail…” << endl;
  6.         mDelegate->onError(kNetwork);
  7.         return;
  8.     }
  9.     vector<string> searchPaths = CCFileUtils::sharedFileUtils()->getSearchPaths();
  10.     vector<string>::iterator iter = searchPaths.begin();
  11.     searchPaths.insert(iter, mFilePath);
  12.     CCFileUtils::sharedFileUtils()->setSearchPaths(searchPaths);
  13.     CCLog(“–2-mFileLenth:%f”,mFileLenth);
  14.     mFileName = mDownloadUrl.substr(mDownloadUrl.rfind(‘/’) + 1);
  15.     CCLog(“–3-”);
  16.     CCLog(“mFileName:%s;”,mFileName.c_str());
  17. //    mFilePath = CCFileUtils::sharedFileUtils()->getWritablePath();
  18. //    CCLog(“–5-”);
  19.     mFilePath = mFilePath + mFileName;
  20.     CCLog(“mFilePath:%s”,mFilePath.c_str());
  21.     CCLog(“–6-”);
  22.     bool ret = false;
  23.     while (true){ // 循环下载 每30秒进行下载 避免断网情况
  24.         ret = download(); //直接下载 进行堵塞线程
  25.         CCLog(“—-stop—%s——”,isStop?”true”:”false”);
  26.         if (isStop) { // 如果进行停止 break
  27.             CCLog(“—-stop———”);
  28.             break;
  29.         }
  30.         if (ret ){ //下载完成
  31.             break;
  32.         }
  33.         sleep(0.5); //每次下载中间间隔0.5秒
  34.     }
  35.     if (ret) {
  36.         CCLog(“download ok”);
  37.         mDelegate->onSuccess(mFilePath);
  38.     } else {
  39.         CCLog(“download fail”);
  40.         mDelegate->onError(kUncompress);
  41.     }
  42. }

3)核心下载

 

 

  1. #pragma mark 进行下载
  2. bool CurlDown::download() {
  3.     FILE *fp = NULL;
  4.     if(access(mFilePath.c_str(), 0)==0) { // 以二进制形式追加
  5.         fp = fopen(mFilePath.c_str(), ”ab+”);
  6.     } else { // 二进制写
  7.         fp = fopen(mFilePath.c_str(), ”wb”);
  8.     }
  9.     if (fp == NULL) {// 如果文件初始化失败进行返回
  10.         return false;
  11.     }
  12.     // 读取本地文件下载大小
  13.     long localFileLenth = getLocalFileLength(); //已经下载的大小
  14.     CCLog(“filePath:%s;leng:%ld”,mFilePath.c_str() , localFileLenth ); //4397779 //3377875
  15.     CURL *handle = curl_easy_init();
  16.     std::string packageUrl = mDownloadUrl; //下载地址+下载文件名
  17.     curl_easy_setopt(handle, CURLOPT_URL, packageUrl.c_str()); // http://curl.haxx.se/libcurl/c/fopen.html
  18.     curl_easy_setopt(handle, CURLOPT_TIMEOUT, timeout);
  19.     curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, my_write_func);   //写文件回调方法
  20.     curl_easy_setopt(handle, CURLOPT_WRITEDATA, fp); // 写入文件对象
  21.     curl_easy_setopt(handle, CURLOPT_RESUME_FROM, localFileLenth);  // 从本地大小位置进行请求数据
  22.     //    curl_easy_setopt(handle, CURLOPT_RESUME_FROM_LARGE, localFileLenth); // 坑
  23.     curl_easy_setopt(handle, CURLOPT_NOPROGRESS, 0L);
  24.     curl_easy_setopt(handle, CURLOPT_PROGRESSFUNCTION, my_progress_func ); //下载进度回调方法
  25.     curl_easy_setopt(handle, CURLOPT_PROGRESSDATA, this); // 传入本类对象
  26.     CURLcode res = curl_easy_perform(handle);
  27.     fclose(fp);
  28.     return res == CURLE_OK;
  29. }

下面大家要问道的就是求源码(^..^)源码已经上传github https://github.com/pingchangxin/BPDownload cesd 下载位置:http://download.csdn.net/detail/vpingchangxin/7108649

 

我这边就再mac上门跑了下 windows的没有进行跑(对win的配置繁琐的头疼了了)