coco2dx c++ 断点续传实现

coco2dx c++ 断点续传实现

实现效果如下

iPhone截图

android 日志截图

流程图如下

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

博客地址:

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

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

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

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

void HelloWorld::menuCallback(CCObject* pSender) {CCMenuItem *item = (CCMenuItem *)pSender;switch (item->getTag()) {case 1: // down startCCDirector::sharedDirector()->getScheduler()->scheduleSelector(schedule_selector(HelloWorld::updateUI), this, 0, false); // HttpClient中参考isStop = false;this->threadStart();break;case 2: // down stopisStop = true;break;case 3:if (isStop) {CCLog("downFilePath:%s",downFilePath.c_str());if (access(downFilePath.c_str(), 0) == 0) {remove(downFilePath.c_str());CCMessageBox("删除成功", "温馨提示");}else{CCMessageBox("没有找到文件目录", "温馨提示");}}else{CCMessageBox("下载中或没有文件下载", "温馨提示");}break;default:break;}}

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

// 启动线程的方法int HelloWorld::threadStart() {pthread_mutex_init(&g_downloadMutex, NULL);int errCode=0;pthread_t th_curlDown; // 线程初始化do {pthread_attr_t tAttr;errCode=pthread_attr_init(&tAttr);CC_BREAK_IF(errCode!=0);errCode=pthread_attr_setdetachstate(&tAttr, PTHREAD_CREATE_DETACHED);if(errCode!=0) {pthread_attr_destroy(&tAttr);break;}errCode=pthread_create(&th_curlDown, &tAttr, thread_funcation, this);} while (0);return errCode;}// 需要线程来完成的功能都写在这个函数里void* HelloWorld::thread_funcation(void *arg) {CCLOG("thread started…");HelloWorld *hw = (HelloWorld*)arg;hw->ccc = new CurlDown("",hw->downFilePath);// ccc->mDownloadUrl = "";// int leng = ccc->getDownloadFileLenth();hw->ccc->setDelegate(hw);hw->ccc->downloadControler();return NULL;}4.实现回调进度、成功、错误(里面用到线程锁对数据进度更新UI,本来对线程就不熟悉,问了群里面的大牛,看了不少资料)void HelloWorld::onError(CurlDown::ErrorCode errorCode){CCLog("error");pthread_mutex_lock(&g_downloadMutex);updateStr = "error";pthread_mutex_unlock(&g_downloadMutex);CCDirector::sharedDirector()->getScheduler()->unscheduleSelector(schedule_selector(HelloWorld::updateUI), this);}void HelloWorld::onProgress(double percent, void *delegate, string filefullPath){ // 下载进度CCLog("donw progress:%.2f%%",percent);if (isStop) {CurlDown * cd = (CurlDown *)delegate;//pthread_mutex_lock(&g_downloadMutex);cd->setStopDown();//pthread_mutex_unlock(&g_downloadMutex);}pthread_mutex_lock(&g_downloadMutex);const char * per =CCString::createWithFormat("donw progress:%.2f%%",percent)->getCString();updateStr = per;downFilePath = filefullPath;pthread_mutex_unlock(&g_downloadMutex);}void HelloWorld::onSuccess(string filefullPath){CCLog("success");pthread_mutex_lock(&g_downloadMutex);updateStr = "success";downFilePath = filefullPath;pthread_mutex_unlock(&g_downloadMutex);}5.CurlDown.hCurlDown.cpp类实现(可以直接抽取出来用于任何地方,没有牵涉到cocos2d-x部分,cocos2d-x部分可以删除没关系)

1)对类初始化

static pthread_mutex_t g_downloadMutex_1;CurlDown::~CurlDown(){mFileLenth = 0;}CurlDown::CurlDown():isStop(false),mDownloadUrl(""),timeout(2){ // test timeout 2 seconds. if release timeout 20 secondsmFileLenth = 0;mFilePath = "";pthread_mutex_init(&g_downloadMutex_1, NULL);}CurlDown::CurlDown(string downUrl,string filePath):mFileLenth(0),isStop(false),mDownloadUrl(downUrl),timeout(2),mFilePath(filePath){ // test timeout 2 seconds. if release timeout 20 secondsmDownloadUrl = downUrl;pthread_mutex_init(&g_downloadMutex_1, NULL);}void CurlDown::setDelegate(CurlDownDelegate * delegate) {mDelegate = delegate;}2)控制下载方法void CurlDown::downloadControler() {CCLog("–1-");mFileLenth = getDownloadFileLenth(); // 获取远程文件大小if (mFileLenth <= 0) {cout << "download file fail…" << endl;mDelegate->onError(kNetwork);return;}vector<string> searchPaths = CCFileUtils::sharedFileUtils()->getSearchPaths();vector<string>::iterator iter = searchPaths.begin();searchPaths.insert(iter, mFilePath);CCFileUtils::sharedFileUtils()->setSearchPaths(searchPaths);CCLog("–2-mFileLenth:%f",mFileLenth);mFileName = mDownloadUrl.substr(mDownloadUrl.rfind(‘/’) + 1);CCLog("–3-");CCLog("mFileName:%s;",mFileName.c_str());// mFilePath = CCFileUtils::sharedFileUtils()->getWritablePath();// CCLog("–5-");mFilePath = mFilePath + mFileName;CCLog("mFilePath:%s",mFilePath.c_str());CCLog("–6-");bool ret = false;while (true){ // 循环下载 每30秒进行下载 避免断网情况ret = download(); //直接下载 进行堵塞线程CCLog("—-stop—%s——",isStop?"true":"false");if (isStop) { // 如果进行停止 breakCCLog("—-stop———");break;}if (ret ){ //下载完成break;}sleep(0.5); //每次下载中间间隔0.5秒}if (ret) {CCLog("download ok");mDelegate->onSuccess(mFilePath);} else {CCLog("download fail");mDelegate->onError(kUncompress);}}3)核心下载#pragma mark 进行下载bool CurlDown::download() {FILE *fp = NULL;if(access(mFilePath.c_str(), 0)==0) { // 以二进制形式追加fp = fopen(mFilePath.c_str(), "ab+");} else { // 二进制写fp = fopen(mFilePath.c_str(), "wb");}if (fp == NULL) {// 如果文件初始化失败进行返回return false;}// 读取本地文件下载大小long localFileLenth = getLocalFileLength(); //已经下载的大小CCLog("filePath:%s;leng:%ld",mFilePath.c_str() , localFileLenth ); //4397779 //3377875CURL *handle = curl_easy_init();std::string packageUrl = mDownloadUrl; //下载地址+下载文件名curl_easy_setopt(handle, CURLOPT_URL, packageUrl.c_str()); // curl_easy_setopt(handle, CURLOPT_TIMEOUT, timeout);curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, my_write_func); //写文件回调方法curl_easy_setopt(handle, CURLOPT_WRITEDATA, fp); // 写入文件对象curl_easy_setopt(handle, CURLOPT_RESUME_FROM, localFileLenth); // 从本地大小位置进行请求数据// curl_easy_setopt(handle, CURLOPT_RESUME_FROM_LARGE, localFileLenth); // 坑curl_easy_setopt(handle, CURLOPT_NOPROGRESS, 0L);curl_easy_setopt(handle, CURLOPT_PROGRESSFUNCTION, my_progress_func ); //下载进度回调方法curl_easy_setopt(handle, CURLOPT_PROGRESSDATA, this); // 传入本类对象CURLcode res = curl_easy_perform(handle);fclose(fp);return res == CURLE_OK;}下面大家要问道的就是求源码(^..^)源码已经上传githubhttps://github.com/pingchangxin/BPDownloadcesd 下载位置:

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

一旦有了意志,脚步也会轻松起来。

coco2dx c++ 断点续传实现

相关文章:

你感兴趣的文章:

标签云: