libcurl使用时疑难问题【如:文件下载】

版权声明:本文为博主原创文章,未经博主允许不得转载。 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 

猜你喜欢

转载自blog.csdn.net/Swallow_he/article/details/83867271