版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Swallow_he/article/details/83867271
场景:
1. 下载过程中,遇设备突然掉电
2. 下载过程中,断网,但是若先断网, 然后进行curl_easy_perform的话,会直接返回失败,不会阻塞
问题:
curl_easy_perform是阻塞的方式进行下载的, curl_easy_perform执行后,程序会在这里阻塞等待下载结束(成功结束或者失败结束).此时若正常下载一段时间后,进行网络中断, curl_easy_perform并不会返回失败,而是阻塞整个程序卡在这里,此时即使网络连接重新恢复, curl_easy_perform也无法恢复继续下载,导致整个程序出现”死机”状态.
之前提供的解决办法:
1.在下载中,另起一个线程,若发现下载状态卡死(可以通过定期检查文件大小来实现),则从外部中断下载线程.此方法需另起线程,而且直接中断线程,会给整个程序带来不稳定.
2.下载过程中,设置超时时间为30秒, 30秒后若下载未完成就重新连接进行下载.
我的解决办法(实际代码)
头文件:
扫描二维码关注公众号,回复:
4123816 查看本文章
/*****************************************************************************
* \File: OperationDownload.h
* \Date: 2018/05/29 15:47
* \Copyright: (C)
* \Author: Administrator
*
* \Brief:
*
* \Version: 1.0.0.0
*
* \Note:
*****************************************************************************/
#ifndef OperationDownload_H
#define OperationDownload_H
#include <list>
#include <mutex>
namespace OpenCloud {
class EventDownloadSession
{
public:
EventDownloadSession(OpenCloud::OpenModelEventDownload *lpOpenModelEventDownload)
:kOpenModelEventDownload(lpOpenModelEventDownload)
{}
virtual ~EventDownloadSession()
{}
virtual int stopSession() = 0;
public:
OpenCloud::OpenModelEventDownload *kOpenModelEventDownload;
};
class OpenEventDownloadInterface
{
public:
virtual int eventDownload(OpenCloud::OpenModelEventDownload * download) = 0;
virtual int eventDownloadStop(OpenCloud::OpenModelEventDownload * download) = 0;
virtual int eventDownloadFlush() = 0;
};
class EventDownloadObserver
{
public:
virtual void OnObserverEventDownloadStart(OpenCloud::EventDownloadSession *lpEventDownloadSession) = 0;
virtual void OnObserverEventDownloadProcess(OpenCloud::EventDownloadSession *lpEventDownloadSession) = 0;
virtual void OnObserverEventDownloadStop(OpenCloud::EventDownloadSession *lpEventDownloadSession) = 0;
};
class EventOperationDownload :public OpenCloud::OpenEventDownloadInterface, public EventDownloadObserver
{
public:
EventOperationDownload();
~EventOperationDownload();
/*
* OpenCloud::OpenEventDownloadInterface
*/
virtual int eventDownload(OpenCloud::OpenModelEventDownload * download);
virtual int eventDownloadStop(OpenCloud::OpenModelEventDownload * download);
virtual int eventDownloadFlush();
/*
* EventDownloadObserver
*/
virtual void OnObserverEventDownloadStart(OpenCloud::EventDownloadSession *lpEventDownloadSession);
virtual void OnObserverEventDownloadProcess(OpenCloud::EventDownloadSession *lpEventDownloadSession);
virtual void OnObserverEventDownloadStop(OpenCloud::EventDownloadSession *lpEventDownloadSession);
public:
std::mutex kEventOperationLock;
std::list<OpenCloud::EventDownloadSession *> kEventOperationSession;
};
} //!namespace OpenCloud
#endif //EventOperationDownload_H
CPP文件:
/*****************************************************************************
* \File: OperationDownload.cpp
* \Date: 2018/05/29 15:47
* \Copyright: (C)
* \Author: Administrator
*
* \Brief:
*
* \Version: 1.0.0.0
*
* \Note:
*****************************************************************************/
#include "OperationDownload.h"
#include "Servlet/ServletObject.h"
#include "Servlet/ServletSynchronization.h"
#include "Servlet/ServletThread.h"
#include "sky_http_client.h" //将libcurl封装成SDK
#include <thread>
#include <memory>
#include <list>
#include <mutex>
namespace OpenCloud {
class EventOperationDownloadSession : public EventDownloadSession
{
public:
EventOperationDownloadSession(OpenCloud::OpenModelEventDownload *lpOpenModelEventDownload, EventDownloadObserver *lpEventDownloadObserver = nullptr)
:EventDownloadSession(lpOpenModelEventDownload), kEventDownloadObserver(lpEventDownloadObserver), kEventDownloadThread(nullptr), kOpenRunning(0)
{
memset(&http_download, 0, sizeof(http_download));
}
virtual ~EventOperationDownloadSession()
{}
virtual void dealloc(void * ref)
{
delete this;
}
static EventOperationDownloadSession * alloc(OpenCloud::OpenModelEventDownload *lpOpenModelEventDownload)
{
EventOperationDownloadSession *lpEventOperationDownloadSession = new EventOperationDownloadSession(lpOpenModelEventDownload);
return lpEventOperationDownloadSession;
}
virtual int Init(void * conf)
{
if (kOpenRunning > 0) return 1;
kOpenRunning = 1;
/*
* EventDownloadObserver
*/
if (kEventDownloadObserver){
kEventDownloadObserver->OnObserverEventDownloadStart(this);
}
int32_t avx_success = 0;
kEventDownloadThread = std::make_shared<std::thread>([this]()
{
thread_entry();
});
kEventDownloadThread->detach(); //注意:如果不添加此语句,可能会导致程序崩溃,一个类中,在线程开始前创建对象,线程执行完毕 销毁对象
return avx_success;
}
virtual int Close()
{
if (kOpenRunning <= 0) return 0;
kOpenRunning = -1;
http_download.running = -1;
int32_t avx_success = 0;
if (kEventDownloadThread&&kEventDownloadThread->joinable()){
kEventDownloadThread->join();
kEventDownloadThread = nullptr;
}
return avx_success;
}
virtual int stopSession()
{
int32_t avx_success = 0;
if (kOpenRunning <= 0) return 0;
kOpenRunning = -1;
http_download.running = -1;
return avx_success;
}
public:
void OnThreadObserverStart()
{
EventDownloadSession *lpEventDownloadSession = static_cast<EventDownloadSession *>(this);
lpEventDownloadSession->AddRef();
}
void OnThreadObserverStop()
{
EventDownloadSession *lpEventDownloadSession = static_cast<EventDownloadSession *>(this);
/*
* EventDownloadObserver
*/
if (kEventDownloadObserver){
kEventDownloadObserver->OnObserverEventDownloadStop(this);
}
//Session Over
lpEventDownloadSession->Release();
}
void OnThreadObserverRun()
{
EventDownloadSession *lpEventDownloadSession = static_cast<EventDownloadSession *>(this);
int32_t avx_success = -1;
int64_t llStartTime = IAVXClock()->TimeMicros();
kOpenModelEventDownload->setRequestTimeStamp(llStartTime);
kOpenModelEventDownload->setDownloadProcess(0);
kOpenModelEventDownload->OnOpenCloudStart(kOpenModelEventDownload);
http_download.progress_cbk_userdata = this;
http_download.progress_cbk = download_file_progress_cbk;
http_download.serv_url = (char *)kOpenModelEventDownload->getDownloadUrl();
http_download.store_path = (char *)kOpenModelEventDownload->getFilePath();
int32_t llTryTimes = 3;
do
{
avx_success = -1;
if (kOpenRunning <= 0) break;
avx_success = sky_http_client_download_file(&http_download);
if (avx_success >= 0)
{
break;
}
} while (--llTryTimes>0);
int64_t llStopsTime = IAVXClock()->TimeMicros();
kOpenModelEventDownload->setResultsTimeStamp(llStopsTime);
kOpenModelEventDownload->setStatusCode(avx_success);
kOpenModelEventDownload->OnOpenCloudResult(kOpenModelEventDownload);
}
void thread_entry()
{
OnThreadObserverStart();
OnThreadObserverRun();
OnThreadObserverStop();
}
protected:
static int download_file_progress_cbk(void *lpUserData, int64_t dltotal, int64_t dlnow)
{
EventOperationDownloadSession *lpEventOperationDownloadSession = (EventOperationDownloadSession *)lpUserData;
OpenCloud::OpenModelEventDownload *lpOpenModelEventDownload = lpEventOperationDownloadSession->kOpenModelEventDownload;
if (dltotal == 0) dltotal = 1;
int32_t llProcessValue = dlnow * 100 / dltotal;
if (lpOpenModelEventDownload->getDownloadProcess() != llProcessValue)
{
lpOpenModelEventDownload->setFileSize(dltotal);
lpOpenModelEventDownload->setFileSeek(dlnow);
lpOpenModelEventDownload->setDownloadProcess(llProcessValue);
lpOpenModelEventDownload->OnOpenCloudProcess(lpOpenModelEventDownload);
}
return 0;
}
public:
EventDownloadObserver *kEventDownloadObserver;
std::shared_ptr<std::thread> kEventDownloadThread;
int32_t kOpenRunning;
http_download_param_t http_download;
};
EventOperationDownload::EventOperationDownload()
{
}
EventOperationDownload::~EventOperationDownload()
{
}
int EventOperationDownload::eventDownload(OpenCloud::OpenModelEventDownload * download)
{
int32_t avx_success = 0;
OpenCloud::EventOperationDownloadSession *lpEventOperationDownloadSession = OpenCloud::EventOperationDownloadSession::alloc(download);
download->setEventDownloadSession(lpEventOperationDownloadSession);
lpEventOperationDownloadSession->kEventDownloadObserver = this;
avx_success = lpEventOperationDownloadSession->Init(nullptr);
return avx_success;
}
int EventOperationDownload::eventDownloadStop(OpenCloud::OpenModelEventDownload * download)
{
int32_t avx_success = 0;
OpenCloud::EventDownloadSession *lpEventOperationDownloadSession = download->getEventDownloadSession();
if (lpEventOperationDownloadSession){
avx_success = lpEventOperationDownloadSession->stopSession();
}
return avx_success;
}
int EventOperationDownload::eventDownloadFlush()
{
std::lock_guard<std::mutex> lock(kEventOperationLock);
std::list<OpenCloud::EventDownloadSession *>::iterator iter = kEventOperationSession.begin();
std::list<OpenCloud::EventDownloadSession *>::iterator ends = kEventOperationSession.end();
while (iter != ends)
{
OpenCloud::EventDownloadSession *lpEventDownloadSession = *iter; iter;
if (lpEventDownloadSession) lpEventDownloadSession->stopSession();
}
return 0;
}
/*
* EventDownloadObserver
*/
void EventOperationDownload::OnObserverEventDownloadStart(OpenCloud::EventDownloadSession *lpEventDownloadSession)
{
do
{
std::lock_guard<std::mutex> lock(kEventOperationLock);
kEventOperationSession.push_back(lpEventDownloadSession);
} while (0);
lpEventDownloadSession->AddRef();
}
void EventOperationDownload::OnObserverEventDownloadProcess(OpenCloud::EventDownloadSession *lpEventDownloadSession)
{
}
void EventOperationDownload::OnObserverEventDownloadStop(OpenCloud::EventDownloadSession *lpEventDownloadSession)
{
do
{
std::lock_guard<std::mutex> lock(kEventOperationLock);
kEventOperationSession.remove(lpEventDownloadSession);
} while (0);
lpEventDownloadSession->Release();
}
} //!namespace OpenCloud