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

📄 downloadmtr.cpp

📁 多线程下载的
💻 CPP
📖 第 1 页 / 共 2 页
字号:
	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;
}

⌨️ 快捷键说明

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