Libcurl中使用curl_easy_perform阻塞, 遇到无信号卡死的完美解决方案

Libcurl中使用curl_easy_perform阻塞, 遇到无信号卡死的完美解决方案

项目背景:  

  近来jwisp在做OMA-DM的android终端侧, 要实现的功能包括FUMO, SCOMO下载管理. 由于项目是基于funambol的开源代码, 在实现FUMO和SCOMO时, 使用了libcurl的库来实现下载服务测的指定文件, 下载后实现android固件升级或android应用下载安装功能, 最后将FUMO/SCOMO的下载安装结果上报给服务端. 需求背景:  

下载流程比较简单, 使用curl_easy_perform即可实现完整的下载流程, 安装后, 使用OMA DM协议上报给平台侧.但是jwisp这里的需求还有两个异常情况需要处理: 

  1. 下载过程中, 遇手机突然掉电(操作:扣电池), android终端再次启动后应能恢复现场然后自动下载, 下载

方式为建议断点续传 

  2. 下载过程中信号中断, 中断时间在5分钟之内, 终端应尝试重新连接, 连接次数在3次以上. 重新连接

后建议使用断点续传方式继续下载.  

但是在使用libcurl时, jwisp发现, curl_easy_perform是阻塞的方式进行下载的, curl_easy_perform执行后, 程序会在这里阻塞等待下载结束(成功结束或者失败结束).此时若正常下载一段时间后, 进行网络中断, curl_easy_perform并不会返回失败, 而是阻塞整个程序卡在这里, 此时即使网络连接重新恢复, curl_easy_perform也无法恢复继续下载, 导致整个程序出现”死机”状态. 

但是若先断网, 然后进行curl_easy_perform的话, 会直接返回失败, 不会阻塞 

在网上搜索后发现, 大家在网上遇到这个问题的很多, 但是解决方法很少, 下面jwisp就把网上建议的可以使用的解决方法罗列:  

  1. 使用multi模式下载, 而不使用easy模式, 此方法的唯一好处就是multi并不会阻塞, 而是立即返回. 但是缺点是带来了问题, 其一就是需要自己去阻塞, 当我们需要返回时再返回, 其二还需要启动一个线程, 需要自己控制整个过程的节奏. 

  2. 在下载中, 另起一个线程, 若发现下载状态卡死(可以通过定期检查文件大小来实现), 则从外部中断下载线程. 此方法需另起线程, 而且直接中断线程, 会给整个程序带来不稳定. 

  在尝试使用网上的方法失败后, jwisp终于设计出了自己的方案, 并完美解决信号中断异常, 下载中掉电异常, 断点续传等问题. 并且此方案不需要启动任何另外的线程, 不需要手动进行阻塞, 在信号中断后, 恢复连接最快可在0.5秒内恢复下载.并且恢复下载方式全部为断点续传. 

  主要的设计思路如下, 下载过程中, 设置超时时间为30秒, 30秒后若下载未完成就重新连接进行下载(这个可解决卡死问题), 每次下载时进行判断, 若不是首次下载则获得当前已下载文件大小, 从该大小处进行续传, 若网络仍处于断开状态, 再次连接会立即返回失败, 此时让当前线程等待0.5秒后进行连接(这个可以解决瞬间恢复连接的问题), 连接次数不超过600次(这个用来保证5分钟后返回失败). 掉电需要在程序已启动时检查是否上次未下载完如果是, 则直接调用下载续传方法即可. 这样基本上所有的问题的流程就都能顺利走下来, 并且下载过程体验好, 可随时取消. 

该方案主要通过两个函数来实现, 一个负责进行断点续传和基本设置, 并执行下载, 一个负责控制整个下载重试次数, 返回下载结果. 并且需要注意的是, 安装完成后, 应将相应的文件删除掉. 

 

你可能感兴趣的:(Libcurl中使用curl_easy_perform阻塞, 遇到无信号卡死的完美解决方案)