加入多线程的文件下载程序

download.h
#pragma once
#include "stdafx.h"

#define BLen 8192
using namespace std;
unsigned int __stdcall Fun(void *pPM);

DWORD SyncWaitForMultipleObjs(HANDLE * handles, int count);
HANDLE  g_hThreadParameter;
CRITICAL_SECTION g_csThreadCode;
long g_nNum; //全局资源
class FileInfo
{
public:
	int Num_Thread;	//线程数
	int blockLen;	//每块长度
	BYTE Buffer[8192];
	int ReadLen;
	int fileLen;
	CFile cf;		//要打开的网页下载文件
	CHttpFile *pF;	//写入文件
}FN1, FN2[10240];

// 多线程下载.cpp: 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include "Download.h"

#define _CRT_SECURE_NO_WARNINGS

LPWSTR MtoW(char* temp, LPTSTR buffera) {

	DWORD dwNum = MultiByteToWideChar(CP_ACP, 0, temp, -1, NULL, 0);
	//计算这个GB2312实际有几个字组成

	wchar_t* pwText;
	pwText = new wchar_t[dwNum];
	if (!pwText)
	{
		delete[]pwText;
	}
	MultiByteToWideChar(CP_ACP, 0, temp, -1, pwText, dwNum);
	//把GB2312变成UNICODE
	wcscpy_s(buffera, MAX_PATH, pwText);
	delete[]pwText;
	return buffera;
}

bool InternetDownload(const CString &strURL, const CString &strFN)
{
	CInternetSession internetSession(L" ",
		1,
		PRE_CONFIG_INTERNET_ACCESS,
		NULL,
		NULL,
		0);

	BOOL bSucceed = TRUE;


		// 统一以二进制方式下载
		DWORD       dwFlag = INTERNET_FLAG_TRANSFER_BINARY | INTERNET_FLAG_DONT_CACHE | INTERNET_FLAG_RELOAD;
		//子类对基类进行了强制类型转换,利用函数打开要下载的网址链接 wangsl
		//将要下载文件的信息
		 FN1.pF = (CHttpFile*)internetSession.OpenURL(strURL, 1, dwFlag);

		// 得到文件大小
		CString      str;
		FN1.pF->QueryInfo(HTTP_QUERY_CONTENT_LENGTH, str);
		FN1.fileLen = _ttoi(str);	//文件大小,将字符串转换成整形
										//int nTotalSize = nFileSize;
		
		cout << "请输入线程数:" << endl;
		//测试时写死
		FN1.Num_Thread = 64;
		FN1.blockLen = FN1.fileLen/FN1.Num_Thread;	//每块长度

		cout << "文件总长度为:" << FN1.fileLen << endl;

		try
		{
			if (FN1.pF != NULL)
			{

				创建下载文件,不存在就创建,存在就直接写入 wangsl
				if (!FN1.cf.Open(strFN, CFile::modeCreate | CFile::modeWrite, NULL))
				{
					return FALSE;
				}
				//添加线程锁
				g_hThreadParameter = CreateMutex(NULL, FALSE, NULL);
				InitializeCriticalSection(&g_csThreadCode);

				HANDLE  handle[MAX_PATH];
				g_nNum = 0;
				int i = 0;
				while (i < FN1.Num_Thread)
				{
					handle[i] = (HANDLE)_beginthreadex(NULL, 0, Fun, &i, 0, NULL);
					WaitForSingleObject(g_hThreadParameter, INFINITE); //等待互斥量被触发  
					i++;
				}
				SyncWaitForMultipleObjs(handle, FN1.Num_Thread);

				//销毁互斥量和关键段  
				CloseHandle(g_hThreadParameter);
				DeleteCriticalSection(&g_csThreadCode);
				for (i = 0; i < FN1.Num_Thread; i++)
					CloseHandle(handle[i]);

				FN1.cf.Close();
				FN1.pF->Close();
				//system("pause");
				delete FN1.pF;

			}
		}
		catch (CInternetException& e)
		{
			char szBuffer[128];
			ZeroMemory(szBuffer, sizeof(szBuffer));
			LPTSTR buffer = NULL;
			MtoW(szBuffer, buffer);
			e.GetErrorMessage(buffer, sizeof(buffer), NULL);
			TRACE("InternetDownload, Exception: %s ", buffer);
		}
		catch (...)
		{
			TRACE("InternetDownload, Exception: ... ");
		}
	internetSession.Close();


	if (!bSucceed)
		DeleteFile(strFN);
	return bSucceed;
}

#define L 2*BLen
unsigned int __stdcall Fun(void *pPM)
{
	int nThreadNum = *(int *)pPM;
	ReleaseMutex(g_hThreadParameter);//触发互斥量  

	Sleep(10);//some work should to do  

	EnterCriticalSection(&g_csThreadCode);
	printf("线程编号为%d  全局资源值为%d\t", nThreadNum, g_nNum);
	
	//写入文件开始 
	int ReadLen = 0;
	BYTE Buffer[BLen];
	ZeroMemory(Buffer, sizeof(Buffer));	//为buffer分配空间
	int offset = g_nNum * FN1.blockLen;	//偏移量
	//如果是文件最后一段
	if (g_nNum == FN1.Num_Thread - 1)
	{
		FN1.blockLen = FN1.fileLen - g_nNum * FN1.blockLen;
	}

	int count = 0;			//统计循环写入长度
	int i = 0;				//统计循环次数
	int Write_Num = FN1.blockLen / BLen + 1;	//写入次数
	int File_tail = FN1.blockLen % BLen;	//文件段末尾

	//FN1.pF->Seek(offset,0);	//查找每块写入位置
	FN1.cf.Seek(offset, CFile::begin);
	
	while (i < Write_Num)
	{
		if (count != BLen * (Write_Num-1))
		{
			ReadLen = FN1.pF->Read(Buffer, BLen);
			FN1.cf.Write(Buffer, ReadLen);
			count += BLen;
			i++;
		}
		else			//如果循环到最后一段 其长度不足或等于Blen 则
		{
			
			ReadLen = FN1.pF->Read(Buffer, File_tail);
			FN1.cf.Write(Buffer, ReadLen);
			i++;
		}
		
	}
	printf("整段长度为:%d\t", FN1.blockLen);cout << count << endl;
	//写入结束
	g_nNum++;
	//Sleep(0);//some work should to do  
	
	LeaveCriticalSection(&g_csThreadCode);


	return 0;
}

//解除最多等待64个线程限制
DWORD SyncWaitForMultipleObjs(HANDLE * handles, int count)
{
	int waitingThreadsCount = count;
	int index = 0;
	DWORD res = 0;
	while (waitingThreadsCount >= MAXIMUM_WAIT_OBJECTS)
	{
		res = WaitForMultipleObjects(MAXIMUM_WAIT_OBJECTS, &handles[index], TRUE, INFINITE);
		if (res == WAIT_TIMEOUT || res == WAIT_FAILED)
		{
			puts("1. Wait Failed.");
			return res;
		}

		waitingThreadsCount -= MAXIMUM_WAIT_OBJECTS;
		index += MAXIMUM_WAIT_OBJECTS;
	}

	if (waitingThreadsCount > 0)
	{
		res = WaitForMultipleObjects(waitingThreadsCount, &handles[index], TRUE, INFINITE);
		if (res == WAIT_TIMEOUT || res == WAIT_FAILED)
		{
			puts("2. Wait Failed.");
		}
	}

	return res;
}

int main()
{
	clock_t start, finish;
	double totaltime;
	

	char str1[] = "http://sqdownb.onlinedown.net/down/ZWCAD2018.exe", str2[] = "1.iso";
	CString ip(str1), name(str2);
	start = clock();
	InternetDownload(ip, name);

	finish = clock();
	totaltime = (double)(finish - start) / CLOCKS_PER_SEC;
	cout << "\n此程序的运行时间为" << totaltime << "秒!" << endl;
	system("pause");
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值