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;
}