⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 downloadpub.cpp

📁 多线程下载的
💻 CPP
📖 第 1 页 / 共 2 页
字号:
// DownloadPub.cpp: implementation of the CDownloadPub class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "NetDownMTR.h"
#include "DownloadPub.h"
// for PathFindExtension () / PathFindFileName ()
#include "Shlwapi.h"
#pragma comment ( lib, "shlwapi.lib" )

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

// 下载数据保存的临时缓冲大小
#define TEMP_SAVE_BUFFER_SIZE		(10*NET_BUFFER_SIZE)
// 当下载的数据达到这个数的时候才保存到文件中
#define WRITE_TEMP_SAVE_MIN_BYTES	(TEMP_SAVE_BUFFER_SIZE - 2*NET_BUFFER_SIZE)
void DownloadNotify ( int nIndex, UINT nNotityType, LPVOID lpNotifyData, LPVOID pDownloadMTR );
// 重试多少次
int g_nRetryTimes = 100;

void SetRetryTimes ( int nRetryTimes )
{
	g_nRetryTimes = nRetryTimes;
}
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CDownloadPub::CDownloadPub()
{
	m_hThread					= NULL;
	m_TimeLastModified			= -1;
	m_csDownloadUrl				= _T("");
	m_csSaveFileName				= _T("");

	m_Proc_SaveDownloadInfo		= NULL;
	m_wSaveDownloadInfo_Param	= NULL;

	m_bSupportResume			= FALSE;
	m_nFileTotalSize			= -1;
	m_csReferer					= _T("");
	m_csUserAgent				= _T("XieHongWei-HttpDown/2.0");
	m_csUsername				= _T("");
	m_csPassword				= _T("");
	m_csProtocolType			= "http";
	m_csServer					= _T("");
	m_csObject					= _T("");
	m_csFileName				= _T("");
	m_nPort						= DEFAULT_HTTP_PORT ;
	m_nIndex					= -1;
	m_csCookieFlag				= _T("");
	ResetVar ();
	m_hEvtEndModule				= ::CreateEvent ( NULL, TRUE, FALSE, NULL );
	m_pDownloadMTR				= NULL;
}

void CDownloadPub::ResetVar()
{
	Clear_Thread_Handle ();
	m_nWillDownloadStartPos		= 0;
	m_nWillDownloadSize			= -1;
	m_nDownloadedSize			= 0;
	m_nTempSaveBytes			= 0;
	m_bDownloadSuccess			= FALSE;
}

CDownloadPub::~CDownloadPub()
{
	StopDownload ();
	Clear_Thread_Handle ();
}

void CDownloadPub::StopDownload ()
{
	m_SocketClient.CancelBlockingCall ();
	if ( HANDLE_IS_VALID(m_hEvtEndModule) )
	{
		::SetEvent ( m_hEvtEndModule );
		WaitForThreadEnd ( m_hThread,30*1000 );
		CLOSE_HANDLE ( m_hEvtEndModule );
		m_hEvtEndModule = NULL;
		Clear_Thread_Handle ();
	}
}

//
// 设置认证信息
//
void CDownloadPub::SetAuthorization ( LPCTSTR lpszUsername, LPCTSTR lpszPassword )
{
	if( lpszUsername != NULL )
	{
		m_csUsername	 = GET_SAFE_STRING(lpszUsername);
		m_csPassword	 = GET_SAFE_STRING(lpszPassword);
	}
	else
	{
		m_csUsername	 = _T("");
		m_csPassword	 = _T("");
	}
}

// 设置Referer
void CDownloadPub::SetReferer(LPCTSTR lpszReferer)
{
	if( lpszReferer != NULL )
		m_csReferer = lpszReferer;
	else
		m_csReferer = _T("");
}

// 设置UserAgent
void CDownloadPub::SetUserAgent(LPCTSTR lpszUserAgent)
{
	m_csUserAgent = lpszUserAgent;	
	if( m_csUserAgent.IsEmpty())
		m_csUserAgent = _T("XieHongWei-HttpDown/2.0");
}

//
// 设置保存下载信息回调函数
//
void CDownloadPub::Set_SaveDownloadInfo_Callback ( FUNC_SaveDownloadInfo Proc_SaveDownloadInfo, WPARAM wParam )
{
	m_Proc_SaveDownloadInfo = Proc_SaveDownloadInfo;
	m_wSaveDownloadInfo_Param = wParam;
}

//
// 下载任务的线程函数
//
DWORD WINAPI ThreadProc_Download(
  LPVOID lpParameter   // thread data
)
{
	CDownloadPub *pDownloadPub = (CDownloadPub*)lpParameter;
	ASSERT ( pDownloadPub );
	return pDownloadPub->ThreadProc_Download ();
}

BOOL CDownloadPub::ThreadProc_Download()
{
	BOOL bRet = FALSE;
	for ( int i=0; i<g_nRetryTimes; i++ )
	{
		if ( DownloadOnce () )
		{
			bRet = TRUE;
			goto finished;
		}
		SLEEP_RETURN_Down ( 5*1000 );
	}

finished:
	TRACE ( "(%d) 线程结束 %s", m_nIndex, bRet?"成功":"失败" );
	return DownloadEnd ( bRet );
}

BOOL CDownloadPub::DownloadOnce()
{
	// 打开文件
	if ( !OpenFileForSave () )
		return FALSE;

	// 连接到服务器
	if ( !m_SocketClient.Is_Connected () )
	{
		if ( !Connect () )
			return FALSE;
	}

	return TRUE;
}

//
// 创建线程下载文件
//
BOOL CDownloadPub::Download (
		int nWillDownloadStartPos,		// 要下载文件的开始位置
		int nWillDownloadSize,			// 本次需要下载的大小,-1表示一直下载到文件尾
		int nDownloadedSize				// 已下载的字节数,指完全写到文件中的字节数
	)
{
	if ( nWillDownloadSize == 0 ) return TRUE;
	// 设置下载参数
	m_nWillDownloadStartPos	= nWillDownloadStartPos;
	Set_WillDownloadSize ( nWillDownloadSize );
	if ( m_nFileTotalSize > 0 && Get_WillDownloadSize() > m_nFileTotalSize )
	{
		Set_WillDownloadSize ( m_nFileTotalSize );
	}
	Set_DownloadedSize ( nDownloadedSize );

	// 创建一个下载线程
	DWORD dwThreadId = 0;
	m_hThread = CreateThread ( NULL, 0, ::ThreadProc_Download, LPVOID(this), 0, &dwThreadId );
	if ( !HANDLE_IS_VALID(m_hThread) )
	{
		Log ( L_WARNING, "(%d) Create download thread failed", m_nIndex );
		return FALSE;
	}
	return TRUE;
}

//
// 下载结束
//
BOOL CDownloadPub::DownloadEnd(BOOL bRes)
{
	m_bDownloadSuccess = bRes;
	m_SocketClient.Disconnect ();
	if ( HANDLE_IS_VALID ( m_file.m_hFile ) )
	{
		m_file.Close ();
	}

	TRACE ( "(%d) %s 结束一次下载\n", m_nIndex, bRes?"成功":"!!! 失败 !!!" );

	return bRes;
}

BOOL CDownloadPub::Connect()
{
	if ( !HANDLE_IS_VALID(m_hEvtEndModule) )
		return FALSE;

	if ( m_csServer.IsEmpty() )
	{
		Log ( L_WARNING, "(%d) Please set download URL", m_nIndex );
		return FALSE;
	}
	m_SocketClient.SetEventOfEndModule ( m_hEvtEndModule );
	m_SocketClient.m_nIndex = m_nIndex;
	// 连接到服务器
	if ( !m_SocketClient.Connect ( m_csServer, m_nPort ) )
		return FALSE;
	Log ( L_NORMAL, "(%d) Connect to server [%s:%d] successfully!", m_nIndex, m_csServer, m_nPort );

	return TRUE;
}

BOOL CDownloadPub::SetDownloadUrl(LPCTSTR lpszDownloadUrl)
{
	if ( !lpszDownloadUrl ) return FALSE;
	m_csDownloadUrl		= lpszDownloadUrl;
	// 检验要下载的URL是否为空
	m_csDownloadUrl.TrimLeft();
	m_csDownloadUrl.TrimRight();
	if( m_csDownloadUrl.IsEmpty() )
		return FALSE;
	// 检验要下载的URL是否有效
	if ( !ParseURL(m_csDownloadUrl, m_csServer, m_csObject, m_nPort, m_csProtocolType))
	{
		TRACE(_T("Failed to parse the URL: %s\n"), m_csDownloadUrl);
		return FALSE;
	}

	return TRUE;
}

//
// 从服务器接收数据并保存到文件中
//
BOOL CDownloadPub::RecvDataAndSaveToFile(CSocketClient &SocketClient,char *szTailData/*=NULL*/, int nTailSize/*=0*/)
{
	int nDownloadedSize = Get_DownloadedSize();
	if ( szTailData && nTailSize > 0 )
	{
		nDownloadedSize = SaveDataToFile ( szTailData, nTailSize );
		if ( nDownloadedSize < 0 )
		{
			return FALSE;
		}
	}

	char szRecvBuf[NET_BUFFER_SIZE] = {0}, *szTempSaveBuf = new char[TEMP_SAVE_BUFFER_SIZE];
	if ( !szTempSaveBuf )
	{
		Log ( L_ERROR, "(%d) Allocate memory failed", m_nIndex );
		return FALSE;
	}
	m_nTempSaveBytes = 0;

	while ( TRUE )
	{
		BOOL bDownloadFinished = FALSE;
		int nReadSize = 0;
		int nTempSaveBytes = Get_TempSaveBytes ();
		int nRecvTotalBytes = nDownloadedSize+nTempSaveBytes;	// 保存在文件中的字节数加上临时缓冲中的字节数就是总共接收到字节数
		int nWillDownloadSize = Get_WillDownloadSize ();
		if	(
				// 从字节数判断,本次下载已经完成了。
				( nWillDownloadSize > 0 && nRecvTotalBytes >= nWillDownloadSize )
				||
				// 模块结束事件有信号,要结束了。
				( ::WaitForSingleObject ( m_hEvtEndModule, 1 ) == WAIT_OBJECT_0 )
			)
		{
			bDownloadFinished = TRUE;
		}
		else
		{
			int nRecvBytesThisTimes = sizeof(szRecvBuf);
			if ( nWillDownloadSize > 0 )
				nRecvBytesThisTimes = nWillDownloadSize - nRecvTotalBytes;
			ASSERT ( nRecvBytesThisTimes >= 0 );
			nRecvBytesThisTimes = MIN ( nRecvBytesThisTimes, sizeof(szRecvBuf) );
			nReadSize = SocketClient.Receive ( szRecvBuf, nRecvBytesThisTimes );
			// 读不到数据了,所以认为下载已经完成
			if ( nReadSize <= 0 )
			{
				if ( nWillDownloadSize <= 0 )
				{
					bDownloadFinished = TRUE;
				}
			}
			else
			{
//				TRACE ( "对象.%d, 收到 %d 字节,我的任务是 %d (0x%08x)字节\n",
//					m_nIndex, nReadSize, nWillDownloadSize , nWillDownloadSize );	//w
			}
		}

		// 先将数据保存到临时缓冲中
		if ( nReadSize > 0 )
		{
			nReadSize = MIN ( nReadSize, TEMP_SAVE_BUFFER_SIZE-nTempSaveBytes );
			memcpy ( szTempSaveBuf+nTempSaveBytes, szRecvBuf, nReadSize );
			nTempSaveBytes += nReadSize;
			ASSERT ( nTempSaveBytes < TEMP_SAVE_BUFFER_SIZE );
		}
		// 当下载已完成或者收到的数据超过一定数量时才保存到文件中
		if ( bDownloadFinished || nTempSaveBytes >= WRITE_TEMP_SAVE_MIN_BYTES )
		{
			// 保存文件失败,下载也应该终止
			nDownloadedSize = SaveDataToFile ( szTempSaveBuf, nTempSaveBytes );
			if ( nDownloadedSize < 0 )
			{
				break;
			}
			nTempSaveBytes = 0;
		}
		Set_TempSaveBytes ( nTempSaveBytes );

		if ( bDownloadFinished )
		{
			ASSERT ( (Get_WillDownloadSize () > 0 && nDownloadedSize >= Get_WillDownloadSize ()) || (nReadSize <= 0 && Get_WillDownloadSize () <= 0) ||
				(::WaitForSingleObject ( m_hEvtEndModule, 1 ) == WAIT_OBJECT_0) );
			break;
		}
	}

	if ( szTempSaveBuf ) delete[] szTempSaveBuf;
	szTempSaveBuf = NULL;

	BOOL bRes = FALSE;
	int nWillDownloadSize = Get_WillDownloadSize ();
	if ( nWillDownloadSize != -1 )
	{
		if ( nDownloadedSize >= nWillDownloadSize )
		{
			bRes = TRUE;
		}
	}
	else if ( nDownloadedSize > 0 )
	{
		bRes = TRUE;
	}
	
	return bRes;
}

int CDownloadPub::SaveDataToFile(char *data, int size)
{
	ASSERT ( HANDLE_IS_VALID ( m_file.m_hFile ) );
	if ( !data || size < 0 ) return -1;

	int nDownloadedSize = -1;
	// 保存下载的数据
	ASSERT ( HANDLE_IS_VALID(m_file.m_hFile) );
	BOOL bRet = TRUE;
	TRY
	{
		m_file.Write ( data, size );
	}
	CATCH( CFileException, e )

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -