微端启动器LAUNCHER的制作之MFC版二(下载)
用了C#再回来用C++写真的有一种我已经不属于这个世界的感觉。C++的下载就没有C#那么方便了,我用的是libcurl.dll,官网上下载的源码自己cmake出来编译的,c++的库引用有debug和release之分,所以刚开始写的时候用的是debug版,然后后来写完了之后改成了release版。
先上代码再来讲吧。
curl_global_init(CURL_GLOBAL_DEFAULT);
curl_global_cleanup();
这个是必须要有的全局初始化和清除,所以我把它放在了下载类的构造和析构里。
下载函数:
CURL * GetConfigCurlHandle = curl_easy_init(); //初始化一个curl,注意线程之间不能共享这个curl,多线程的话就每个线程自己设置一个curl
FtpFile ftpfile = { FileName.data(), NULL };
string strpath = Config::GetInstance()->m_sDownloadFile + "\\" + FileName;
fopen_s(&ftpfile.stream, strpath.data(), "ab+"); //一定要有+不然下一次写入就把之前的覆盖了
curl_easy_setopt(GetConfigCurlHandle, CURLOPT_URL, url.data()); //注册url
curl_easy_setopt(GetConfigCurlHandle, CURLOPT_WRITEFUNCTION, DownloadCallback); //注册一个回调函数用于写入文件
curl_easy_setopt(GetConfigCurlHandle, CURLOPT_WRITEDATA, &ftpfile);
curl_easy_setopt(GetConfigCurlHandle, CURLOPT_BUFFERSIZE, CURL_MAX_WRITE_SIZE); //设置缓冲区大小
ConfigRetcCode = curl_easy_perform(GetConfigCurlHandle);
if (ftpfile.stream)
{
string str = ftpfile.filename;
//Config::GetInstance()->WriteLog("关闭文件"+str);
fclose(ftpfile.stream);
}
if (ConfigRetcCode != CURLE_OK)
{
int co = ConfigRetcCode;
string str = FileName + "下载失败errorcode:"+Config::GetInstance()->FloatToString(co);
Config::GetInstance()->WriteLog(str);
if (ConfigRedownloadTime<10)
{
DownloadConfigFile(url, FileName);
}
ConfigRedownloadTime++;
}
else
{
return;
}
下载全部结束之后要清除这个curl:
curl_easy_cleanup(GetConfigCurlHandle);
有两个比较重要的坑了我的点,一个就是注册url的那里,我的url是string类型,直接传入string类型是不会报错的,但是这个下载会返回一个错误,错误码我不记得了大概就是找不到这个url的意思。而传入url.data()就没错了,也就是相当于把string转成了char*。其实C++中很多的函数都是不能识别string类型的参数的,在c++中传参还是少用string的好。至于原因哪个大牛能告诉我一下好想知道!!!写c#的时候只想怎么用,但是写c++就好想知道原理是怎么回事!
第二个点是我把打开文件和关闭文件的函数放在了回调函数中,但是如果是一个大文件的话他是没有办法一次就写完的,所以就会不断地去调用回调函数写入文件,也就会不断地打开和关闭,然后就出现了文件被占用导致写入失败的问题。这个我真的查了很久的原因,因为c++不像C#,C++的报错总是在很底层,我常说c++总是断在神奇的位置。于是我把下载线程屏蔽掉然后在主线程中循环的打开关闭这个文件夹,在打开和关闭中做一些耗时操作,结果并没有报错那说明文件并没有被其他线程占用,那么也就只可能是下载线程的问题。但是网上所有的关于这个libcurl下载大文件的问题都没有解释。后来有个大牛朋友跟我说了一个直写和后写的问题,他说文件写入磁盘分为直写和后写,直写就是调用写入函数的时候就写入磁盘,后写就是过一会再写入磁盘。我不知道具体的原因但是这个给了我启发,是不是文件写入磁盘的时候还没有写完而我就进行了下一次打开写入操作,虽然每一次打开文件之后我都关闭了文件,但是他仅仅只是对文件的操作成功了,而操作系统还在继续把文件写入磁盘中,所以导致下一次写入的时候报错的错误码是文件被占用。而我把打开和关闭操作放在了回调函数外也就是一个文件只进行一次打开和关闭就没有问题了。不知道自己的想法对不对希望有大牛能给我解释一下具体原因。跪谢~~~
还有一个点是我在C#中用http下载没有遇到过的就是下载失败的问题,下载失败原因很多,看错误码基本都是网络问题啊什么的,所有加入了一个循环递归,如果下载不成功就循环下载十次直到成功,如果十次还不成功那就只能告诉玩家你网不好待会再来吧。。。。。。这个在C#中没有遇到过可能是http自己封装了下载失败的处理程序吧。
微端启动器LAUNCHER的制作之MFC版二(下载)的更多相关文章
- 微端游戏启动器LAUNCHER的制作之MFC版一(序和进程通信)
额...刚开始信誓旦旦说要写launcher制作的博客,还没写完就被抛到脑后了真是没毅力.最近把之前写的wpf的launcher改成了mfc版,遇到很多问题,写了三个星期才写完,好好记录一下吧.我也想 ...
- 微端游戏启动器launcher的制作(序篇)
公司要做一个游戏接入腾讯QQ游戏大厅,腾讯要求制作一个launcher,公司之前并没有接入过腾讯,所以大家其实都不懂,而我又是新人,所以刚拿到这个任务的时候整个人就是一个大写的懵逼.在网上查找了不少的 ...
- 微端游戏启动器launcher的制作之下载篇(系列一)
首先第一篇先讲一讲launcher最核心的功能---下载功能. 这个部分估计得好几篇才能写完,东西比较多也比较杂,慢慢来吧,我的东西也在继续改进中...... 从web上下载文件需要用到几个类,Htt ...
- dotNet开发游戏微端
需求分析 功能要求 当玩家使用不支持 unity webplayer 的浏览器进入游戏时,让玩家通过微端玩游戏. 确保微端的功能和页游戏功能一致. 大体功能就是为unity web game开发微端, ...
- Egret微端 创建项目(一)
开发环境: window7 egret engine:5.0.14 egret wing:4.1.0 微端:v0.0.14 官方教程:http://developer.egret.com/cn/git ...
- 2D客户端+微端技术总结
本人于2013年9月23号加入一个页游项目组, 并作为项目组的客户端小组的主程, 带领一个4个人(峰值)的前端小组, 进行微端的开发.微端项目于2014年8月底大体完成, 历时11个月.9月份之后微端 ...
- 微端 代码project as air 分享
分享 ^_^ 1. 使用 air , as . 2. 微端下载和更新技术 成功上线棋牌游戏.它可用于传统的游戏开发. 地址: http://download.csdn.net/detail/stone ...
- Unity下的开发框架--适应web和微端游戏异步资源请求的框架
一. 内容简介: 1. 框架对Web与微端游戏特性的支持: Web和微端游戏最重要的特性是,资源是持续从服务器上即时下载下来的.而保证体验流畅的关键就是保证资源下载分散到持续的体验过程中,并保 ...
- 微端 打包更新工具 as air 分享
分享 微端,更新的是散包,不像端游,一个大包搞定. 更新须要每次用工具把资源的散文件.依据文件夹结构及时间 生成一个列表, 每次更新就是 文件夹及时间的比对! 该project能够翻译成 其它语言.有 ...
随机推荐
- mysql之SQL---存储过程
1.存储过程简介 我们常用的操作数据库语言SQL语句在执行的时候需要要先编译,然后执行,而存储过程(Stored Procedure)是一组为了完成特定功能的SQL语句集,经编译后存储在数据库中,用 ...
- 一、Hadoop基本操作命令
查看hadoop版本 hadoop version 启动与关闭 启动Hadoop 1. 进入HADOOP_HOME目录. 2. 执行sh bin/start-all.s ...
- jstl-按照html的形式输出至页面
一.按照html的形式输出至页面 <c:out value="${xxx}" default="默认值" escapeXml="false&qu ...
- winscp 秘钥登录
如题 如果不想用密码登录,可以选择用秘钥文件登录winscp 原理和linux分发ssh公钥是一个道理 1:在被管理的机器上分发公钥 ,出现 authorized_keys才可以 完成服务端配置 2: ...
- VS2010环境下用ANSI C创建DLL和使用方法(转)
源:VS2010环境下用ANSI C创建DLL和使用方法 . 创建DLL工程 1.2 创建一个dll工程. 操作:a.文件->新建->项目->Win32控制台应用程序. b.输入工程 ...
- mybatis--常见的错误
1.没有在configuration.xml配置对应的sql配置文件 错误: Error updating database. Cause: java.lang.IllegalArgumentExce ...
- vuejs 父组件向子组件传递($broadcast()的用法)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- zepto js 源码 解读
/* Zepto v1.0-1-ga3cab6c - polyfill zepto detect event ajax form fx - zeptojs.com/license */ ;(funct ...
- perl访问数组中变量
数组一个是存储标量值的无序列表变量. 数组变量以 @ 开头.访问数组元素使用 $ + 变量名称 + [索引值] 格式来读取,实例如下: #!/usr/bin/perl @names = (" ...
- Java语言与C语言之间的应用比较
http://book.51cto.com/art/200906/131809.htm C语言能干的Java也能干的如下: 网络应用层协议服务程序开发:如WebServer.FTPServer.Mai ...