cocos2dx 使用libcurl进行文件传输
来源:互联网 发布:矩阵分解的应用 编辑:程序博客网 时间:2024/05/22 00:40
CURL是cocos2dx推荐的网络传输库。它包括阻塞传输方式和非阻塞传输方式。在这里值用到了阻塞方式。
本文基于资源在线更新的工作内容讲了3个问题:
设置文件搜寻路径
文件对比方式
非阻塞传输在网络中断情况的解决方法。
文章所用的方法参考了jwisp专栏。网址如下 http://blog.csdn.net/javarat/article/details/8002198点击打开链接
CURL简单传输的方法如下:
CURL *curl_easy_init(void); //初始化一个传输
CURLcode curl_easy_setopt(CURL *curl, CURLoption option, ...); //设置传输参数
CURLcode curl_easy_perform(CURL *curl); //执行传输
void curl_easy_cleanup(CURL *curl); //清理
注意:执行完一次传输后,如果进行了清理操作,下一次传输前还要进行初始化。
(一) 设置文件搜寻路径
资源的存储方式将分为一开始就打包到App中的部分,和从网络下载的部分。从网络下载的部分存储位置是docmennt目录,这个位置是CCFileUtil::sharedFileUtils()->getWritablePath()获取的。CCFileUtil类提供了设置搜寻路径方法,把document路径加入CCFileUtil的搜寻路径集合中,把它设置成第一搜寻路径,则通过CCFileUtil读取文件时,会先从document目录下查找,没有的话再从默认路径(app)查找。
设置方式如下:
_storagePath =CCFileUtils::sharedFileUtils()->getWritablePath();void CurlTest::setSearchPath(){ vector<string> searchPaths = CCFileUtils::sharedFileUtils()->getSearchPaths(); vector<string>::iterator iter = searchPaths.begin(); searchPaths.insert(iter, _storagePath); CCFileUtils::sharedFileUtils()->setSearchPaths(searchPaths);}
(二)文件对比更新
有了搜寻路径,下一步对比版本文件,把版本更新的文件下载到document目录下。客户端app打包默认打进一个version.plist文件,对比操作过程如下:
(1)从服务器端下载 version.plis文件,先命名为version_temp.plist
(2)查找document目录下有没有version.plist,没有的话查找app中的这个文件
(3)对比version_temp.plist 和 version.plist ,plist文件中每个文件对应一个版本号,每下载一个文件,就跟更新一次version.plist,并且修改完后存储 version.plist文件。 防止掉电重新开始的时候要从头下载。
(4) 下载完成后,删除旧版的version.plist把 version_temp.plist重命名为version.plist
我们使用的是单线程的阻塞方式传输,即在传输过程中线程是阻塞的。如果在请求传输之前,也就是
curl_easy_perform( CURL *curl)操作之前,网络是不可用的,这个方法能立刻返回失败,不导致阻塞。如果传输过程中网络中断,则会一直处于curl_easy_perform( CURL *curl)状态,不能退出,导致卡死状态。关于这点,我们利用了断点续传,解决方式如下:
设置一个传输时间timeout,单位是秒。在timeout时间内,如果文件传输完毕,返回成功,否则超过了timenout,返回失败。
设置传输次数times,在times时间内可以可以一直请求传输,超过这个请求次数,判定网络故障无法连接。
那么一个文件最长的传输时间是 T = timeout * 传输次数 ;
我们设定每隔0.5秒请求一次传输,如果发生网络中断,请求连接时间超过1分钟判定为网络故障。则请求的次数应该是 0.5秒 * 120次 =60秒。
可以根据网速设置一个单次传输时间,我们先设置成timeout = 30秒。网速先按照10k/s来计算。一个2M的文件,它的传输时间是205秒,那么传输次数至少是7次。
这样在我们设定的网速(10k/s),最大文件(2M),和单次传输时间(30秒)上,计算传传输次数(7次),再加上请求连接1分钟判定网络故障。
得出 times = 7 + 120; 这个参数可以根据具体情况修改。
发生网络故障时候,最长阻塞时间应该是 单次传输时间 + 大约1分钟请求连接时间。
代码如下
单个文件下载:
bool CurlTest:: download(long timeout,std::string filename){std::string fullpath = _storagePath + filename;FILE *fp = NULL;if(access(fullpath.c_str(), 0)==0){fp = fopen(fullpath.c_str(), "ab+"); //追加方式打开}else{fp = fopen(fullpath.c_str(), "wb"); //创建方式打开}if(fp==NULL){ return false ;}long localFileLenth = getLocalFileLenth(filename.c_str()); //已经下载的大小CURLcode res;std::string packageUrl = downloadUrl + filename; //下载地址+下载文件名curl_easy_setopt(_curl, CURLOPT_URL, packageUrl.c_str());curl_easy_setopt(_curl, CURLOPT_TIMEOUT, timeout); //timeout秒下载时间curl_easy_setopt(_curl, CURLOPT_WRITEFUNCTION, downLoadPackage); //写文件回调方法curl_easy_setopt(_curl, CURLOPT_WRITEDATA, fp);curl_easy_setopt(_curl, CURLOPT_RESUME_FROM, localFileLenth); //断点续传位置curl_easy_setopt(_curl, CURLOPT_NOPROGRESS, 0);curl_easy_setopt(_curl, CURLOPT_PROGRESSFUNCTION, progressFunc ); //下载进度回调方法res = curl_easy_perform(_curl);fclose(fp);if (res!=0) {return false;} else {return true;}}//控制方法void CurlTest::downloadControler(std::string filename){int count = 0;bool ret = false;while (count++ < DOWNLOAD_TIMES){ret = download(DOWNLOAD_TIMEOUT,filename); //直接下载if (ret ){ //下载完成break;}sleep(0.5); //每次下载中间间隔0.5秒}if (ret ) {if( std::string::npos != filename.find(".zip") && uncompress(filename.c_str()) ){CCLog(" 解压成功 %s",filename.c_str());remove((_storagePath+filename).c_str()); //删除 .zip}CCLog(" 下载完成");}else{CCLog("下载失败 网络故障");}}
获取本地文件大小
long CurlTest::getLocalFileLenth(const char* filename){ std::string fullPath = CCFileUtils::sharedFileUtils()->getWritablePath() + filename;FILE *fp = fopen(fullPath.c_str(), "r");fseek(fp, 0, SEEK_END);long length = ftell(fp);fclose(fp);return length;}
字典存储成pilst方法
void CurlTest::dictionaryWriteToPlist(CCDictionary *dictionary,const char * filename){std::string plist_save_path = CCFileUtils::sharedFileUtils()->getWritablePath()+filename;XMLDocument doc;XMLDeclaration *declare =doc.NewDeclaration("xml version=\"1.0\" encoding=\"UTF-8\"");doc.LinkEndChild(declare);XMLElement *element = doc.NewElement("dict");doc.LinkEndChild(element);CCArray *array = dictionary->allKeys();for (int i=0; i<dictionary->count(); i++) {XMLElement *eleKey = doc.NewElement("key");XMLText *textKey = doc.NewText(((CCString*)array->objectAtIndex(i))->getCString());eleKey->LinkEndChild(textKey);XMLElement *eleValue = doc.NewElement("integer");std::string valueKey = ((CCString*)(array->objectAtIndex(i)))->m_sString;CCLOG(valueKey.c_str());XMLText *textValue = doc.NewText(((CCString*)(dictionary->valueForKey(valueKey)))->getCString());eleValue->LinkEndChild(textValue);element->LinkEndChild(eleKey);element->LinkEndChild(eleValue);}doc.SaveFile(plist_save_path.c_str());}
curl回调方法:这个两个方法必须是静态全局的。
static int progressFunc(void *ptr, double totalToDownload, double nowDownloaded, double totalToUpLoad, double nowUpLoaded){//当前下载文件的总体大小totalToDownload //当前下载的大小nowDownloaded//当前下载的文件进度 float curpercent =nowDownloaded / totalToDownload *100; return 0;}
static size_t downLoadPackage(void *ptr, size_t size, size_t nmemb, void *userdata){FILE *fp = (FILE*)userdata;size_t written = fwrite(ptr, size, nmemb, fp);return written;}
感谢jwisp专栏。
- cocos2dx 使用libcurl进行文件传输
- 使用libcurl实现跨平台文件传输
- 使用libcurl实现跨平台文件传输
- 使用串口进行文件传输
- 使用Netty进行文件传输
- 使用TFTP进行文件传输
- 使用Netty进行文件传输
- 使用secureCRT进行文件传输
- 使用 Thrift 进行文件传输
- 使用libcurl进行文件上传
- 使用libcurl进行文件上传
- 使用gFTP进行安全文件传输
- 使用NDK进行网络文件传输
- 使用FTP自动进行文件传输
- 使用libcurl库进行HTTP的下载
- 使用libcurl进行文件、数据上传
- 使用C#进行点对点通讯和文件传输
- 使用C#进行点对点通讯和文件传输
- Linux shell脚本全面学习-------http://www.1987.name/shell--另一个牛逼的shell教程
- 【整理】CentOS 网络设置修改
- Xcode快捷键
- java exec() 改变工作目录
- [转载]QSqlQuery Select、Insert、Update、Delete操作
- cocos2dx 使用libcurl进行文件传输
- Qt中使用setStyleSheet对QPushButton按钮进行外观设置
- UILineBreakMode的各种情况
- 关于SetMapMode坐标变换以后的BitBlt使用
- Mysql 慢查询和慢查询日志分析
- ndk 开发笔记
- c++ 那么多内存分配函数(GlobalAlloc,new,malloc等)的关系
- as3 常用验证
- photoshop图层之"正片叠底"