您的位置:首页 > 编程语言 > C语言/C++

vc++ 实现多线程断点续传

2014-07-30 10:39 134 查看
结合FTP类,http类,实现多线程断点续传

// DownloadMTR.cpp: implementation of the CDownloadMTR class.

//

//////////////////////////////////////////////////////////////////////

#include "stdafx.h"

#include "downtest.h"

#include "DownloadMTR.h"

#include <io.h>

#ifdef _DEBUG

#undef THIS_FILE

static char THIS_FILE[]=__FILE__;

#define new DEBUG_NEW

#endif

void DownloadNotify ( int nIndex, UINT nNotityType, LPVOID lpNotifyData, LPVOID pDownloadMTR );

//////////////////////////////////////////////////////////////////////

// Construction/Destruction

//////////////////////////////////////////////////////////////////////

CDownloadMTR::CDownloadMTR()

: m_nThreadCount ( DEFAULT_THREAD_COUNT )

, m_pDownloadPub_MTR ( NULL )

, m_pDownloadPub_Info ( NULL )

, m_pDownloadCellInfo ( NULL )

, m_hThread ( NULL )

, m_bForceDownload ( FALSE )

, m_nTotalDownloadedSize_ThisTimes ( 0 )

{

memset ( &m_BaseDownInfo, 0, sizeof(t_BaseDownInfo) );

m_hEvtEndModule = ::CreateEvent ( NULL, TRUE, FALSE, NULL );

m_dwDownloadStartTime = GetTickCount();

}

CDownloadMTR::~CDownloadMTR()

{

StopDownload ();

}

//

// 设置下载的线程数

//

BOOL CDownloadMTR::SetThreadCount(int nThreadCount)

{

if ( nThreadCount <= 0 || nThreadCount > MAX_DOWNLOAD_THREAD_COUNT )

{

Log ( L_WARNING, "Thread count %d is invalid. Rang [%d-%d]", nThreadCount, 1, MAX_DOWNLOAD_THREAD_COUNT );

return FALSE;

}

if ( nThreadCount == m_nThreadCount )

return TRUE;

m_nThreadCount = nThreadCount;

return TRUE;

}

//

// 下载任务的线程函数

//

DWORD WINAPI ThreadProc_DownloadMTR(

LPVOID lpParameter // thread data

)

{

CDownloadMTR *pDownloadMTR = (CDownloadMTR*)lpParameter;

ASSERT ( pDownloadMTR );

pDownloadMTR->ThreadProc_DownloadMTR ();

TRACE ( "下载任务的线程函数 执行完毕/n" );

return TRUE;

}

BOOL CDownloadMTR::ThreadProc_DownloadMTR()

{

// 启动多线程下载任务

int nRet = StartMTRDownload ();

if ( nRet == 2 ) return HandleDownloadFinished(ENUM_DOWNLOAD_RESULT_SUCCESS);

if ( nRet == 0 ) return HandleDownloadFinished(ENUM_DOWNLOAD_RESULT_FAILED);

// 等待所有线程下载完成

ENUM_DOWNLOAD_RESULT eDownloadResult = WaitForDownloadFinished ();

if ( eDownloadResult == ENUM_DOWNLOAD_RESULT_SUCCESS && !GetDownloadResult () )

{

eDownloadResult = ENUM_DOWNLOAD_RESULT_FAILED;

}

return HandleDownloadFinished ( eDownloadResult );

}

//

// 多线程断点续传下载一个文件

//

BOOL CDownloadMTR::Download (

LPCTSTR lpszDownloadURL,

LPCTSTR lpszSavePath,

LPCTSTR lpszSaveOnlyFileName,

LPCTSTR lpszUsername/*=NULL*/,

LPCTSTR lpszPassword/*=NULL*/,

BOOL bForceDownload/*=FALSE*/ // 如果为 TRUE 表示强制性重新下载,以下载的部分将会被删除,FALSE 表示断点续传

)

{

if ( !HANDLE_IS_VALID(m_hEvtEndModule) )

return FALSE;

if ( !lpszSavePath || strlen(lpszSavePath) < 1 )

return FALSE;

m_csSavePath = lpszSavePath;

m_csSaveOnlyFileName = GET_SAFE_STRING(lpszSaveOnlyFileName);

m_bForceDownload = bForceDownload;

CString csServer, csObject;

USHORT nPort = 0;

if ( !ParseURL ( lpszDownloadURL, csServer, csObject, nPort, m_csProtocolType ) )

{

Log ( L_ERROR, "Download URL [%s] invalid", lpszDownloadURL );

return FALSE;

}

m_csDownloadURL = lpszDownloadURL;

// 创建取站点信息对象

if ( !( m_pDownloadPub_Info = CreateDownloadObject () ) )

{

Log ( L_ERROR, "Create download object failed" );

return HandleDownloadFinished(ENUM_DOWNLOAD_RESULT_FAILED);

}

// 设置取站点信息对象的参数

m_pDownloadPub_Info->SetAuthorization ( lpszUsername, lpszPassword );

m_pDownloadPub_Info->m_pDownloadMTR = this;

m_pDownloadPub_Info->SetDownloadUrl ( lpszDownloadURL );

// 创建一个下载线程

DWORD dwThreadId = 0;

m_hThread = CreateThread ( NULL, 0, ::ThreadProc_DownloadMTR, LPVOID(this), 0, &dwThreadId );

if ( !HANDLE_IS_VALID(m_hThread) )

{

Log ( L_WARNING, "Create download thread failed" );

return FALSE;

}

return TRUE;

}

//

// 创建下载对象

//

CDownloadPub* CDownloadMTR::CreateDownloadObject ( int nCount/*=1*/ )

{

if ( nCount < 1 ) return NULL;

CDownloadPub *pDownloadPub = NULL;

if ( m_csProtocolType.CompareNoCase ( "http" ) == 0 )

{

pDownloadPub = (CDownloadPub*)new CDownloadHttp[nCount];

}

else if ( m_csProtocolType.CompareNoCase ( "ftp" ) == 0 )

{

pDownloadPub = (CDownloadPub*)new CDownloadFtp[nCount];

}

else return NULL;

return pDownloadPub;

}

//

// 删除下载对象

//

void CDownloadMTR::DeleteDownloadObject ( CDownloadPub *pDownloadPub )

{

if ( m_csProtocolType.CompareNoCase ( "http" ) == 0 )

{

delete[] ( (CDownloadHttp*)pDownloadPub );

}

else if ( m_csProtocolType.CompareNoCase ( "ftp" ) == 0 )

{

delete[] ( (CDownloadFtp*)pDownloadPub );

}

else delete[] pDownloadPub;

}

void Callback_SaveDownloadInfo ( int nIndex, int nDownloadedSize, int nSimpleSaveSize, WPARAM wParam )

{

CDownloadMTR *pDownloadMTR = (CDownloadMTR*)wParam;

ASSERT ( pDownloadMTR );

pDownloadMTR->Callback_SaveDownloadInfo ( nIndex, nDownloadedSize, nSimpleSaveSize );

}

void CDownloadMTR::Callback_SaveDownloadInfo ( int nIndex, int nDownloadedSize, int nSimpleSaveSize )

{

if ( nIndex >= 0 && nIndex < m_nThreadCount )

{

m_pDownloadCellInfo[nIndex].nDownloadedSize = nDownloadedSize;

if ( nDownloadedSize > 0 )

{

m_CSFor_DownloadedData.Lock();

m_nTotalDownloadedSize_ThisTimes += nSimpleSaveSize;

m_CSFor_DownloadedData.Unlock ();

}

}

}

//

// 创建多线程下载使用的对象和数据缓冲

//

BOOL CDownloadMTR::CreateDownloadObjectAndDataMTR ()

{

DeleteDownloadObjectAndDataMTR ();

ASSERT ( !m_pDownloadPub_MTR && m_pDownloadPub_Info );

m_pDownloadPub_MTR = CreateDownloadObject ( m_nThreadCount );

// 设置多线程下载使用的对象的参数

if ( m_pDownloadPub_MTR )

{

for ( int nIndex=0; nIndex<m_nThreadCount; nIndex++ )

{

m_pDownloadPub_MTR[nIndex].m_nIndex = nIndex;

m_pDownloadPub_MTR[nIndex].m_pDownloadMTR = this;

m_pDownloadPub_MTR[nIndex].Set_SaveDownloadInfo_Callback ( ::Callback_SaveDownloadInfo, WPARAM(this) );

m_pDownloadPub_MTR[nIndex].SetAuthorization ( m_pDownloadPub_Info->Get_UserName(), m_pDownloadPub_Info->Get_GetPassword() );

m_pDownloadPub_MTR[nIndex].SetDownloadUrl ( m_csDownloadURL );

if ( !m_pDownloadPub_MTR[nIndex].SetSaveFileName ( GetTempFilePath() ) )

return FALSE;

}

}

// 创建多线程下载使用的数据缓冲

ASSERT ( !m_pDownloadCellInfo );

m_pDownloadCellInfo = new t_DownloadCellInfo[m_nThreadCount];

if ( m_pDownloadCellInfo )

memset ( m_pDownloadCellInfo, 0, m_nThreadCount*sizeof(t_DownloadCellInfo) );

if ( m_pDownloadPub_MTR != NULL && m_pDownloadCellInfo != NULL )

return TRUE;

Log ( L_WARNING, "Create MTR download object or buffer failed" );

return FALSE;

}

//

// 删除多线程下载使用的对象和数据缓冲

//

void CDownloadMTR::DeleteDownloadObjectAndDataMTR()

{

if ( m_pDownloadPub_MTR )

{

DeleteDownloadObject ( m_pDownloadPub_MTR );

m_pDownloadPub_MTR = NULL;

}

if ( m_pDownloadCellInfo )

{

delete[] m_pDownloadCellInfo;

m_pDownloadCellInfo = NULL;

}

}

//

// 删除取站点信息的下载对象

//

void CDownloadMTR::DeleteDownloadObject_Info()

{

if ( m_pDownloadPub_Info )

{

DeleteDownloadObject ( m_pDownloadPub_Info );

m_pDownloadPub_Info = NULL;

}

}

//

// 启动多线程下载,返回 0 表示失败,1表示成功,2表示不用下载了,因为该文件已经下载过了

//

int CDownloadMTR::StartMTRDownload ()

{

m_dwDownloadStartTime = GetTickCount();

DownloadNotify ( -1, NOTIFY_TYPE_START_DOWNLOAD, (LPVOID)NULL, this );

// 先获取站点信息

ASSERT ( m_pDownloadPub_Info );

if ( !m_pDownloadPub_Info->GetRemoteSiteInfo () )

return 0;

DbgLog ( "要下载的文件大小是: %d 字节/n", m_pDownloadPub_Info->Get_FileTotalSize () );

StandardSaveFileName ();

CFileStatus fileStatus;

if ( m_bForceDownload )

{

// 需要重新下载

::DeleteFile ( m_csSavePathFileName );

::DeleteFile ( GetTempFilePath() );

}

else

{

// 要保存的文件是否已经存在,且大小和创建时间一致,如果不是强制性下载,则不需要再下载了。

if ( CFile::GetStatus(m_csSavePathFileName,fileStatus) )

{

if (

(

fileStatus.m_mtime.GetTime() - m_pDownloadPub_Info->Get_TimeLastModified() <=2 &&

m_pDownloadPub_Info->Get_TimeLastModified()-fileStatus.m_mtime.GetTime() <=2

)

&&

fileStatus.m_size == m_pDownloadPub_Info->Get_FileTotalSize ()

&&

!m_bForceDownload

)

{

return 2;

}

}

}

BOOL bMustCreateNullFile = TRUE;

// 读取下载信息,如果能读到说明上次下载尚未完成

if ( !m_bForceDownload && m_pDownloadPub_Info->Is_SupportResume() )

{

if ( CFile::GetStatus(GetTempFilePath(),fileStatus) &&

fileStatus.m_size == m_pDownloadPub_Info->Get_FileTotalSize()+GetDownloadInfoWholeSize() )

{

if ( ReadDownloadInfo () )

bMustCreateNullFile = FALSE;

}

}

if ( bMustCreateNullFile )

{

int nFileSize = m_pDownloadPub_Info->Get_FileTotalSize();

int nTempFileSize = nFileSize+GetDownloadInfoWholeSize();

if ( nFileSize < 0 || !m_pDownloadPub_Info->Is_SupportResume() )

nTempFileSize = 0;

// 创建一个用来保存下载数据的空文件

if ( !CreateNullFile ( GetTempFilePath(), nTempFileSize ) )

return FALSE;

}

// 分配下载任务

if ( !AssignDownloadTask () )

{

Log ( L_WARNING, "Assign task failed" );

return 0;

}

m_dwDownloadStartTime = GetTickCount();

return 1;

}

//

// 得到临时数据保存的路径文件名

//

CString CDownloadMTR::GetTempFilePath ()

{

ASSERT ( !m_csSavePathFileName.IsEmpty () );

CString csTempFileName;

csTempFileName.Format ( "%s.~xhw~", m_csSavePathFileName );

::SetFileAttributes ( csTempFileName, FILE_ATTRIBUTE_HIDDEN );

return csTempFileName;

}

//

// 分配下载任务

//

BOOL CDownloadMTR::AssignDownloadTask()

{

ASSERT ( m_pDownloadPub_Info );

if ( !m_pDownloadPub_Info->Is_SupportResume() )

{

DeleteDownloadObjectAndDataMTR ();

Log ( L_WARNING, "Site [%s] not support resume download", m_pDownloadPub_Info->Get_ServerName() );

}

// 文件大小未知,采用单线程

if ( m_pDownloadPub_Info->Get_FileTotalSize () <= 0 || !m_pDownloadPub_Info->Is_SupportResume() )

{

if ( m_nThreadCount != 1 )

{

DeleteDownloadObjectAndDataMTR ();

SetThreadCount ( 1 );

}

}

if ( !DownloadInfoIsValid() || !m_pDownloadPub_MTR || !m_pDownloadCellInfo )

{

if ( !CreateDownloadObjectAndDataMTR () )

return FALSE;

}

ASSERT ( m_pDownloadPub_MTR && m_pDownloadCellInfo );

// 下载任务尚未分配

if ( !DownloadInfoIsValid() )

{

int nWillDownloadSize = -1, nWillDownloadStartPos = 0, nNoAssignSize = 0;

if ( m_pDownloadPub_Info->Get_FileTotalSize () > 0 )

{

nWillDownloadSize = m_pDownloadPub_Info->Get_FileTotalSize () / m_nThreadCount;

// 均分后剩下的部分,让第一个线程来承担下载

nNoAssignSize = m_pDownloadPub_Info->Get_FileTotalSize () % m_nThreadCount;

}

DbgLog ( "任务分配如下:--------------------/n" );

for ( int nIndex=0; nIndex<m_nThreadCount; nIndex++ )

{

m_pDownloadCellInfo[nIndex].nWillDownloadStartPos = nWillDownloadStartPos;

m_pDownloadCellInfo[nIndex].nWillDownloadSize = nWillDownloadSize;

if ( nIndex == 0 && m_pDownloadPub_Info->Get_FileTotalSize () > 0 )

{

m_pDownloadCellInfo[nIndex].nWillDownloadSize += nNoAssignSize;

}

DbgLog ( "线程.%d 从 %d(0x%08x) 下载到 %d(0x%08x) 共 %d(0x%08x) 字节/n", nIndex,

m_pDownloadCellInfo[nIndex].nWillDownloadStartPos, m_pDownloadCellInfo[nIndex].nWillDownloadStartPos,

m_pDownloadCellInfo[nIndex].nWillDownloadStartPos+m_pDownloadCellInfo[nIndex].nWillDownloadSize,

m_pDownloadCellInfo[nIndex].nWillDownloadStartPos+m_pDownloadCellInfo[nIndex].nWillDownloadSize,

m_pDownloadCellInfo[nIndex].nWillDownloadSize, m_pDownloadCellInfo[nIndex].nWillDownloadSize );

nWillDownloadStartPos += m_pDownloadCellInfo[nIndex].nWillDownloadSize;

}

}

// 启动下载任务

for ( int nIndex=0; nIndex<m_nThreadCount; nIndex++ )

{

if ( !m_pDownloadPub_MTR[nIndex].Download ( m_pDownloadCellInfo[nIndex].nWillDownloadStartPos,

m_pDownloadCellInfo[nIndex].nWillDownloadSize, m_pDownloadCellInfo[nIndex].nDownloadedSize ) )

return FALSE;

}

m_BaseDownInfo.dwThreadCount = m_nThreadCount;

return TRUE;

}

//

// 从下载信息文件中读取下载信息

//

BOOL CDownloadMTR::ReadDownloadInfo()

{

CString csTempFileName = GetTempFilePath ();

BOOL bRet = FALSE;

CFile file;

TRY

{

if ( file.Open ( csTempFileName, CFile::modeCreate|CFile::modeNoTruncate|CFile::modeReadWrite|CFile::typeBinary|CFile::shareDenyNone ) )

{

if ( file.Seek ( -(int)sizeof(t_BaseDownInfo), CFile::end ) == (int)(file.GetLength() - sizeof(t_BaseDownInfo)) )

{

if ( (UINT)file.Read ( &m_BaseDownInfo, sizeof(t_BaseDownInfo) ) == sizeof(t_BaseDownInfo) )

{

if ( (m_BaseDownInfo.dwThreadCount > 0 && m_BaseDownInfo.dwThreadCount <= MAX_DOWNLOAD_THREAD_COUNT)&&

SetThreadCount ( m_BaseDownInfo.dwThreadCount ) )

{

if ( CreateDownloadObjectAndDataMTR () )

{

if ( file.Seek ( -GetDownloadInfoWholeSize(), CFile::end ) == int(file.GetLength() - GetDownloadInfoWholeSize()) )

{

if ( file.Read ( m_pDownloadCellInfo, sizeof(t_DownloadCellInfo)*m_nThreadCount ) == sizeof(t_DownloadCellInfo)*m_nThreadCount )

{

bRet = TRUE;

}

else

{

memset ( m_pDownloadCellInfo, 0, sizeof(t_DownloadCellInfo)*m_nThreadCount );

}

}

}

}

}

}

}

}

CATCH( CFileException, e )

{

e->Delete ();

bRet = FALSE;

}

END_CATCH

if ( HANDLE_IS_VALID(file.m_hFile) )

file.Close ();

return bRet;

}

BOOL CDownloadMTR::SaveDownloadInfo ()

{

if ( !m_pDownloadPub_Info->Is_SupportResume() )

return TRUE;

CString csTempFileName = GetTempFilePath ();

BOOL bRet = FALSE;

CFile file;

TRY

{

if ( file.Open ( csTempFileName, CFile::modeCreate|CFile::modeNoTruncate|CFile::modeReadWrite|CFile::typeBinary|CFile::shareDenyNone ) )

{

if ( file.Seek ( -(int)sizeof(t_BaseDownInfo), CFile::end ) == (int)(file.GetLength() - sizeof(t_BaseDownInfo)) )

{

file.Write ( &m_BaseDownInfo, sizeof(t_BaseDownInfo) );

if ( file.Seek ( -GetDownloadInfoWholeSize(), CFile::end ) == int(file.GetLength() - GetDownloadInfoWholeSize()) )

{

file.Write ( m_pDownloadCellInfo, m_nThreadCount*sizeof(t_DownloadCellInfo) );

bRet = TRUE;

}

}

}

}

CATCH( CFileException, e )

{

e->Delete ();

bRet = FALSE;

}

END_CATCH

if ( HANDLE_IS_VALID ( file.m_hFile ) )

file.Close ();

if ( !bRet ) Log ( L_WARNING, "Save download info failed. %s", hwFormatMessage ( GetLastError() ) );

return bRet;

}

BOOL CDownloadMTR::HandleDownloadFinished(ENUM_DOWNLOAD_RESULT eDownloadResult)

{

CString csTempFileName;

CFileStatus fileStatus;

BOOL bRet = FALSE;

CFile file;

if ( eDownloadResult != ENUM_DOWNLOAD_RESULT_SUCCESS )

{

SaveDownloadInfo ();

goto Finished;

}

csTempFileName = GetTempFilePath ();

// 设置文件大小

if ( m_pDownloadPub_Info->Is_SupportResume() && m_pDownloadPub_Info->Get_FileTotalSize() > 0 )

{

TRY

{

file.Open ( csTempFileName, CFile::modeCreate|CFile::modeNoTruncate|CFile::modeReadWrite|CFile::typeBinary|CFile::shareDenyNone );

file.SetLength(m_pDownloadPub_Info->Get_FileTotalSize ());

bRet = TRUE;

}

CATCH( CFileException, e )

{

e->Delete ();

bRet = FALSE;

}

END_CATCH

if ( HANDLE_IS_VALID(file.m_hFile) )

file.Close ();

if ( !bRet )

{

Log ( L_WARNING, "Set [%s] length failed", csTempFileName );

eDownloadResult = ENUM_DOWNLOAD_RESULT_FAILED;

goto Finished;

}

}

if ( _access(csTempFileName,04) == 0 )

{

// 将文件改名

bRet = FALSE;

DeleteFile ( m_csSavePathFileName );

TRY

{

CFile::Rename ( csTempFileName, m_csSavePathFileName );

bRet = TRUE;

}

CATCH( CFileException, e )

{

e->Delete ();

bRet = FALSE;

}

END_CATCH

if ( !bRet )

{

Log ( L_WARNING, "Rename [%s] failed. %s", csTempFileName, hwFormatMessage(GetLastError()) );

eDownloadResult = ENUM_DOWNLOAD_RESULT_FAILED;

goto Finished;

}

// 设置文件属性,时间设置和服务器一致

bRet = FALSE;

if ( CFile::GetStatus(m_csSavePathFileName,fileStatus) )

{

fileStatus.m_mtime = m_pDownloadPub_Info->Get_TimeLastModified();

fileStatus.m_attribute = CFile::normal;

CFile::SetStatus ( m_csSavePathFileName, fileStatus );

bRet = TRUE;

}

if ( !bRet )

{

Log ( L_WARNING, "Set file [%s] status failed. %s", csTempFileName, hwFormatMessage(GetLastError()) );

eDownloadResult = ENUM_DOWNLOAD_RESULT_FAILED;

goto Finished;

}

}

Finished:

DownloadNotify ( -1, NOTIFY_TYPE_END_DOWNLOAD, (LPVOID)eDownloadResult, this );

return bRet;

}

BOOL CDownloadMTR::GetDownloadResult()

{

for ( int nIndex=0; nIndex<m_nThreadCount; nIndex++ )

{

if ( !m_pDownloadPub_MTR[nIndex].Is_DownloadSuccess() )

return FALSE;

}

return TRUE;

}

//

// 下载信息是否有效

//

BOOL CDownloadMTR::DownloadInfoIsValid()

{

BOOL bValid = FALSE;

int nIndex = 0;

if ( !m_pDownloadCellInfo ) goto Invalid;

if ( m_BaseDownInfo.dwThreadCount < 1 || m_BaseDownInfo.dwThreadCount > MAX_DOWNLOAD_THREAD_COUNT )

goto Invalid;

for ( nIndex=0; nIndex<m_nThreadCount; nIndex++ )

{

if ( m_pDownloadCellInfo[nIndex].nWillDownloadSize > 0 )

{

bValid = TRUE;

break;

}

}

if ( !bValid ) goto Invalid;

return TRUE;

Invalid:

if ( m_pDownloadCellInfo )

memset ( m_pDownloadCellInfo, 0, m_nThreadCount*sizeof(t_DownloadCellInfo) );

memset ( &m_BaseDownInfo, 0, sizeof(t_BaseDownInfo) );

return FALSE;

}

//

// 找到剩余未下载的数量最大的那个对象编号

//

int CDownloadMTR::GetUndownloadMaxBytes( int &nUndownloadBytes )

{

nUndownloadBytes = 0;

int nMaxIndex = -1;

for ( int nIndex=0; nIndex<m_nThreadCount; nIndex++ )

{

int nTempBytes = m_pDownloadPub_MTR[nIndex].GetUndownloadBytes ();

if ( nUndownloadBytes < nTempBytes )

{

nUndownloadBytes = nTempBytes;

nMaxIndex = nIndex;

}

}

return nMaxIndex;

}

//

// 编号为 nIndex 的对象调度任务,为下载任务最繁重的对象减轻负担

//

BOOL CDownloadMTR::AttemperDownloadTask(int nIndex)

{

ASSERT ( m_pDownloadPub_MTR && m_pDownloadCellInfo );

if ( m_nThreadCount <= 1 || m_pDownloadCellInfo[nIndex].nWillDownloadSize == -1 )

return FALSE;

int nUndownloadBytes = 0;

int nIndex_Heavy = GetUndownloadMaxBytes ( nUndownloadBytes );

if ( nIndex_Heavy == -1 || nIndex_Heavy == nIndex )

return FALSE;

if ( m_pDownloadPub_MTR[nIndex_Heavy].ThreadIsRunning() && nUndownloadBytes < 100*1024 )

return FALSE;

ASSERT ( nIndex_Heavy >= 0 && nIndex_Heavy < m_nThreadCount );

ASSERT ( m_pDownloadPub_MTR[nIndex_Heavy].Get_WillDownloadStartPos() == m_pDownloadCellInfo[nIndex_Heavy].nWillDownloadStartPos );

DbgLog ( "下载对象.%d 帮 %d (%s) 减轻负担/n", nIndex, nIndex_Heavy, m_pDownloadPub_MTR[nIndex_Heavy].ThreadIsRunning()?"运行":"停止" );

// 给空闲下载对象分配新任务

m_pDownloadCellInfo[nIndex].nWillDownloadSize = ( m_pDownloadPub_MTR[nIndex_Heavy].ThreadIsRunning()?(nUndownloadBytes/2) : nUndownloadBytes );

m_pDownloadCellInfo[nIndex].nWillDownloadStartPos = m_pDownloadPub_MTR[nIndex_Heavy].Get_WillDownloadStartPos() +

m_pDownloadPub_MTR[nIndex_Heavy].Get_WillDownloadSize() - m_pDownloadCellInfo[nIndex].nWillDownloadSize;

m_pDownloadCellInfo[nIndex].nDownloadedSize = 0;

DbgLog ( "空闲下载对象.%d 分配新任务: %d(0x%08x) - %d(0x%08x) 共 %d(0x%08x)/n", nIndex, m_pDownloadCellInfo[nIndex].nWillDownloadStartPos, m_pDownloadCellInfo[nIndex].nWillDownloadStartPos,

m_pDownloadCellInfo[nIndex].nWillDownloadStartPos + m_pDownloadCellInfo[nIndex].nWillDownloadSize, m_pDownloadCellInfo[nIndex].nWillDownloadStartPos + m_pDownloadCellInfo[nIndex].nWillDownloadSize,

m_pDownloadCellInfo[nIndex].nWillDownloadSize, m_pDownloadCellInfo[nIndex].nWillDownloadSize );

// 启动空闲下载对象的下载任务

if ( m_pDownloadCellInfo[nIndex].nWillDownloadSize == 0 )

return FALSE;

m_pDownloadPub_MTR[nIndex].ResetVar ();

if ( !m_pDownloadPub_MTR[nIndex].Download ( m_pDownloadCellInfo[nIndex].nWillDownloadStartPos,

m_pDownloadCellInfo[nIndex].nWillDownloadSize, m_pDownloadCellInfo[nIndex].nDownloadedSize ) )

return FALSE;

// 减轻繁忙下载对象的任务

m_pDownloadCellInfo[nIndex_Heavy].nWillDownloadSize -= m_pDownloadCellInfo[nIndex].nWillDownloadSize;

m_pDownloadPub_MTR[nIndex_Heavy].Set_WillDownloadSize ( m_pDownloadCellInfo[nIndex_Heavy].nWillDownloadSize );

DbgLog ( "繁忙下载对象.%d 下载了 %d(0x%08x) 未完 %d(0x%08x) 字节,调整任务为: %d(0x%08x) - %d(0x%08x) 共 %d(0x%08x)/n",

nIndex_Heavy, m_pDownloadPub_MTR[nIndex_Heavy].Get_DownloadedSize(), m_pDownloadPub_MTR[nIndex_Heavy].Get_DownloadedSize(),

nUndownloadBytes, nUndownloadBytes,

m_pDownloadCellInfo[nIndex_Heavy].nWillDownloadStartPos, m_pDownloadCellInfo[nIndex_Heavy].nWillDownloadStartPos,

m_pDownloadCellInfo[nIndex_Heavy].nWillDownloadStartPos + m_pDownloadCellInfo[nIndex_Heavy].nWillDownloadSize, m_pDownloadCellInfo[nIndex_Heavy].nWillDownloadStartPos + m_pDownloadCellInfo[nIndex_Heavy].nWillDownloadSize,

m_pDownloadCellInfo[nIndex_Heavy].nWillDownloadSize, m_pDownloadCellInfo[nIndex_Heavy].nWillDownloadSize );

return TRUE;

}

//

// 等待下载结束

//

ENUM_DOWNLOAD_RESULT CDownloadMTR::WaitForDownloadFinished()

{

ASSERT ( HANDLE_IS_VALID(m_hEvtEndModule) );

int nCount = m_nThreadCount + 1;

ENUM_DOWNLOAD_RESULT eDownloadResult = ENUM_DOWNLOAD_RESULT_FAILED;

HANDLE *lpHandles = new HANDLE[nCount];

if ( !lpHandles ) goto End;

while ( TRUE )

{

nCount = 0;

for ( int nIndex=0; nIndex<m_nThreadCount; nIndex++ )

{

HANDLE hThread = m_pDownloadPub_MTR[nIndex].Get_Thread_Handle ();

if ( HANDLE_IS_VALID(hThread) )

lpHandles[nCount++] = hThread;

}

lpHandles[nCount++] = m_hEvtEndModule;

if ( nCount == 1 )

{

if ( Get_TotalDownloadedSize() >= m_pDownloadPub_Info->Get_FileTotalSize() )

{

ASSERT ( Get_TotalDownloadedSize() == m_pDownloadPub_Info->Get_FileTotalSize() );

eDownloadResult = ENUM_DOWNLOAD_RESULT_SUCCESS;

}

else

eDownloadResult = ENUM_DOWNLOAD_RESULT_FAILED;

goto End;

}

int nRet = (int)WaitForMultipleObjects ( nCount, lpHandles, FALSE, INFINITE ) - WAIT_OBJECT_0;

// 某下载对象完成任务了

if ( nRet >= 0 && nRet < nCount-1 )

{

nIndex = FindIndexByThreadHandle ( lpHandles[nRet] );

if ( ( nIndex >= 0 && nIndex < m_nThreadCount ) )

{

if ( !m_pDownloadPub_MTR[nIndex].Is_DownloadSuccess() ||

!AttemperDownloadTask ( nIndex ) )

{

m_pDownloadPub_MTR[nIndex].Clear_Thread_Handle ();

}

}

else

{

eDownloadResult = ENUM_DOWNLOAD_RESULT_CANCEL;

goto End;

}

}

// 模块结束

else

{

eDownloadResult = ENUM_DOWNLOAD_RESULT_CANCEL;

goto End;

}

}

End:

// 等待所有下载线程结束

if ( eDownloadResult != ENUM_DOWNLOAD_RESULT_SUCCESS )

{

nCount = 0;

for ( int nIndex=0; nIndex<m_nThreadCount; nIndex++ )

{

HANDLE hThread = m_pDownloadPub_MTR[nIndex].Get_Thread_Handle ();

if ( HANDLE_IS_VALID(hThread) )

lpHandles[nCount++] = hThread;

}

WaitForMultipleObjects ( nCount, lpHandles, TRUE, 500*1000 );

}

if ( lpHandles ) delete[] lpHandles;

return eDownloadResult;

}

int CDownloadMTR::FindIndexByThreadHandle(HANDLE hThread)

{

for ( int nIndex=0; nIndex<m_nThreadCount; nIndex++ )

{

HANDLE hThread_Temp = m_pDownloadPub_MTR[nIndex].Get_Thread_Handle ();

if ( HANDLE_IS_VALID(hThread_Temp) && hThread_Temp == hThread )

return nIndex;

}

return -1;

}

int CDownloadMTR::GetDownloadInfoWholeSize()

{

return ( sizeof(t_DownloadCellInfo)*m_nThreadCount + sizeof(t_BaseDownInfo) );

}

//

// 获取下载所消耗的时间(毫秒),可用来计算下载速度和推算剩余时间

//

DWORD CDownloadMTR::GetDownloadElapsedTime()

{

return (GetTickCount() - m_dwDownloadStartTime);

}

//

// 停止下载。将所有下载线程关闭,将下载对象删除,文件关闭

//

void CDownloadMTR::StopDownload()

{

if ( HANDLE_IS_VALID(m_hEvtEndModule) )

{

::SetEvent ( m_hEvtEndModule );

}

// 设置多线程下载使用的对象的参数

if ( m_pDownloadPub_MTR )

{

for ( int nIndex=0; nIndex<m_nThreadCount; nIndex++ )

{

m_pDownloadPub_MTR[nIndex].StopDownload ();

}

}

if ( m_pDownloadPub_Info )

{

m_pDownloadPub_Info->StopDownload ();

}

if ( HANDLE_IS_VALID(m_hThread) )

{

WaitForThreadEnd ( m_hThread,100*1000 );

CLOSE_HANDLE ( m_hThread )

}

DeleteDownloadObjectAndDataMTR ();

DeleteDownloadObject_Info ();

CLOSE_HANDLE ( m_hEvtEndModule );

}

void CDownloadMTR::StandardSaveFileName ()

{

ASSERT ( m_csSavePath.GetLength() > 0 );

StandardizationPathBuffer ( m_csSavePath.GetBuffer(MAX_PATH), MAX_PATH );

m_csSavePath.ReleaseBuffer ();

MakeSureDirectory ( m_csSavePath );

char szOnlyFileName_NoExt_User[MAX_PATH] = {0};

char szExtensionName_User[MAX_PATH] = {0};

// 如果用户指定了新的保存文件名,就用新的。

if ( m_csSaveOnlyFileName.GetLength() > 0 )

{

CString csFileNameByURL = GetLocalFileNameByURL ( m_csDownloadURL );

if ( csFileNameByURL.CompareNoCase(m_csSaveOnlyFileName) != 0 )

{

PartFileAndExtensionName ( m_csSaveOnlyFileName, szOnlyFileName_NoExt_User, MAX_PATH, szExtensionName_User, MAX_PATH );

}

}

CString csExtensionName_Remote;

CString csFileName_Remote = m_pDownloadPub_Info->GetDownloadObjectFileName ( &csExtensionName_Remote );

if ( strlen(szOnlyFileName_NoExt_User) > 0 )

{

if ( strlen(szExtensionName_User) < 1 )

STRNCPY_CS ( szExtensionName_User, csExtensionName_Remote );

m_csSavePathFileName.Format ( "%s%s.%s", StandardizationFileForPathName(m_csSavePath,FALSE),

StandardizationFileForPathName(szOnlyFileName_NoExt_User,TRUE), StandardizationFileForPathName(szExtensionName_User,TRUE) );

}

else

{

m_csSavePathFileName.Format ( "%s%s", StandardizationFileForPathName(m_csSavePath,FALSE), StandardizationFileForPathName(csFileName_Remote,TRUE) );

}

}

//

// 根据 URL 来获取本地保存的文件名

//

CString CDownloadMTR::GetLocalFileNameByURL ( LPCTSTR lpszDownloadURL )

{

if ( !lpszDownloadURL || strlen(lpszDownloadURL) < 1 )

return "";

char szOnlyPath[MAX_PATH] = {0};

char szOnlyFileName[MAX_PATH] = {0};

if ( !PartFileAndPathByFullPath ( lpszDownloadURL, szOnlyFileName, MAX_PATH, szOnlyPath, MAX_PATH ) )

return "";

return szOnlyFileName;

}

//

// 获取文件大小

//

int CDownloadMTR::Get_FileTotaleSize()

{

if ( !m_pDownloadPub_Info ) return -1;

return m_pDownloadPub_Info->Get_FileTotalSize ();

}

//

// 获取已下载的字节数,包括以前下载的和本次下载的

//

int CDownloadMTR::Get_TotalDownloadedSize()

{

if ( !m_pDownloadPub_Info ) return -1;

int nTotalUndownloadBytes = 0;

for ( int nIndex=0; nIndex<m_nThreadCount; nIndex++ )

{

nTotalUndownloadBytes += m_pDownloadPub_MTR[nIndex].GetUndownloadBytes();

}

int nFileSize = m_pDownloadPub_Info->Get_FileTotalSize();

if ( nFileSize < 1 ) return -1;

// 文件大小减去未完成的,就是已下载的

return ( nFileSize - nTotalUndownloadBytes );

}

int CDownloadMTR::Get_TotalDownloadedSize_ThisTimes()

{

m_CSFor_DownloadedData.Lock ();

int nTotalDownloadedSize_ThisTimes = m_nTotalDownloadedSize_ThisTimes;

m_CSFor_DownloadedData.Unlock ();

return nTotalDownloadedSize_ThisTimes;

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: