C 语言 GET请求 超小纯净下载工具 (支持http、https)第四季

第一季简单实现了下载功能:C 语言http GET请求 超小纯净下载工具 (暂时只支持http)第一季_trw777的博客-CSDN博客

第二季主要修改功能:​​​​​​C 语言http GET请求 超小纯净下载工具 (暂时只支持http)第二季_trw777的博客-CSDN博客

1、域名有几个IP,建几个线程下载,线程可成倍怎加,但有些域名会有8个IP,线程太多。

2、单挑线程20秒收不到数据,重新换IP建联,连续40秒下载速度低,重新换IP建联。

第三季主要修改功能:

C 语言http GET请求 超小纯净下载工具 (暂时只支持http,支持大文件下载)第三季_trw777的博客-CSDN博客

1、将文件处理方式修改为内存映射,以便能快速处理大文件。

2、某个进程下载完成之后分担其他进程的数据下载

第四季主要修改功能:添加支持https单线程下载功能(下一季添加HTTP多线程下载)。

源代码地址:trw / 下载 · GitCode

https功能实现可参考:C 语言 https(SSL)客户端简单实现_trw777的博客-CSDN博客

代码组成部分分为:头文件--1.global.h ,源文件--字符转换(2.ANSI_to_UTF8.cpp), 下载功能(3.Download.cpp) 和 主流程main(4.main.cpp) 

头文件

1.  global.h

#pragma once
#include						//输入输出-文件
#include						//C++输入输出-文件
#include					//SOCKET网络连接
#include						//多线程头文件
#include					//互斥锁头文件,可不添加从Winsock2.h可以连接到
using namespace std;
#pragma comment(lib, "ws2_32.lib")

#define TNUM 1
extern HANDLE hMutex;					//全局互斥锁
extern int errq;						//全局错误码
extern int thread;						//全局线程数
extern WSADATA WsaData;					//全局SCOKET库
extern float MaxSpeed ;					//全局单线程最大速度
extern char MaxIP[16];					//全局最大速度的IP

//保存URL信息
typedef struct httpurl {
	char Http[6] = "";					//协议头
	char Host[64] = "";					//域名
	char Directories[256] = "";			//目录
	char Filename[128] = "";			//文件名
	int  IPType = 0;					//IP类型
	int  IPPort = 0;					//端口
	char IP[16][16] = { "" };			//文本IP
	int	 IPnum = 0;						//IP数量
}HTTPURL, * PHTTPURL;

//保存HTTP请求信息
typedef struct resphead {
	char Statusline[32] = "";			//请求行
	long ContentLength = 0;				//文件大小
	long ContentBlock = 0;				//块大小
	char ContentMD5[40] = "";			//文件MD5验证码
	bool Breakpoint = false;			//是否支持断点下载
}RESPHEAD, * PRESPHEAD;

//保存下载缓存文件休息
typedef struct threadtmp {
	int ThreadId = 0;					//线程ID
	char ThreadIP[16] = "";				//是否保存完成
	FILE* ThreadFtmp = nullptr;			//缓存文件
	long ThreadBlock = 0;				//块大小
	long ThreadStart = 0;				//文件开始位置
	long ThreadSize = 0;				//已经下载大小
	long ThreadEnd = 0;					//文件结束位置
	bool DownComplete = false;			//是否下载完成
	bool SaveComplete = false;			//是否保存完成
}THREADTMP, * PTHREADTMP;

//保存下载缓存文件休息
typedef struct threadMtmp {
	int ThreadId = 0;					//线程ID
	char ThreadIP[16] = "";				//是否保存完成
	DWORD ThreadBlock = 0;				//块大小
	DWORD ThreadStart = 0;				//文件开始位置
	DWORD ThreadSize = 0;				//已经下载大小
	DWORD ThreadEnd = 0;				//文件结束位置
	char ThreadName[128] = "";			//缓存文件名
	int ThreadShare = 0;				//分担次数
	bool ShareBool = false;				//分担触发
	HANDLE FileMapTmp = nullptr;		//缓存文件映射
	bool DownComplete = false;			//是否下载完成
	bool SaveComplete = false;			//是否保存完成
}THREADMTMP, * PTHREADMTMP;

//线程信息
typedef struct Param {
	PHTTPURL phu = nullptr;				//URL结构体指针
	PRESPHEAD prh = nullptr;			//Http请求结构体指针
	PTHREADTMP ftmp;					//缓存文件结构体
	PTHREADMTMP mtmp;					//缓存文件结构体
	int n = 0;							//线程号
	bool DownComplete = false;			//下载完成
}PARAM, * PPARAM;

源文件

2.  ANSI_to_UTF8.cpp

#include 
#include 
#define BUFF_SIZE 1024
#pragma warning(disable : 4075)
#pragma warning(disable : 4996)
#pragma warning(disable : 6387)

/*多字符转换为宽字符 --- ANSI -to- Unicode*/
wchar_t* ANSIToUnicode(const char* str)
{
    int textlen;
    wchar_t* result;
    textlen = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
    result = (wchar_t*)malloc((textlen + 1) * sizeof(wchar_t));
    if (nullptr != (result = (wchar_t*)malloc((textlen + 1) * sizeof(wchar_t))))
    {
        memset(result, 0, (textlen + 1) * sizeof(wchar_t));
        MultiByteToWideChar(CP_ACP, 0, str, -1, (LPWSTR)result, textlen);
        return result;
    }
    return 0;
}

/*宽字符转换为多字符 --- Unicode -to- ANSI*/
char* UnicodeToANSI(const wchar_t* str)
{
    char* result;
    int textlen;
    textlen = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
    result = (char*)malloc((textlen + 1) * sizeof(char));
    if (nullptr != result)
    {
        memset(result, 0, sizeof(char) * (textlen + 1));
        WideCharToMultiByte(CP_ACP, 0, str, -1, result, textlen, NULL, NULL);
        return result;
    }
    return 0;
}

/*UTF8转换为宽字符 --- UTF8 -to- Unicode */
wchar_t* UTF8ToUnicode(const char* str)
{
    int textlen;
    wchar_t* result;
    textlen = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0);
    result = (wchar_t*)malloc((textlen + 1) * sizeof(wchar_t));
    if (nullptr != result)
    {
        memset(result, 0, (textlen + 1) * sizeof(wchar_t));
        MultiByteToWideChar(CP_UTF8, 0, str, -1, (LPWSTR)result, textlen);
        return result;
    }
    return 0;
}

/*宽字符转换为UTF8 --- Unicode -to- UTF8 */
char* UnicodeToUTF8(const wchar_t* str)
{
    char* result;
    int textlen;
    textlen = WideCharToMultiByte(CP_UTF8, 0, str, -1, NULL, 0, NULL, NULL);
    result = (char*)malloc((textlen + 1) * sizeof(char));
    if (nullptr != result)
    {
        memset(result, 0, sizeof(char) * (textlen + 1));
        WideCharToMultiByte(CP_UTF8, 0, str, -1, result, textlen, NULL, NULL);
        return result;
    }
    return 0;
}

/*多字符转换为UTF8 --- Unicode -to- UTF8 */
char* ANSIToUTF8(const char* str)
{
    return UnicodeToUTF8(ANSIToUnicode(str));
}

/*UTF8转换为多字符 --- UTF8 -to- ANSI */
char* UTF8ToANSI(const char* str)
{
    return UnicodeToANSI(UTF8ToUnicode(str));
}

3.  Download.cpp

#include"global.h"
#include
#include
#include 
#include
#include 
#include
#pragma comment(lib,"libssl.lib")
#pragma comment(lib,"libcrypto.lib")

#define SENDBUFSIZE 1460
#define RECVBUFSIZE 8192
#define BLOCKSIZE 65536
#pragma warning(disable : 4996)

long FsizeNew = 0;
SOCKADDR_IN addr = { 0 };
char ReqHead[512] = "";
int MaxShare = 1;

//多字节转UTF函数
char* ANSIToUTF8(const char* str);
//初始化URL结构体
int InitHttpurl(PHTTPURL phu) {
	//删除文件加下的的所有缓存文件
	for (int i = 0; i < thread; i++)
	{
		char mtmp[64] = "";
		sprintf_s(mtmp, "./Download/download-%02d.tmp", i);
		remove(mtmp);
		/*DeleteFile(mtmp);*/
	}
	
	char Url[256] = "";
	cout << "\n\n请输入下载地址:";
	scanf_s("%[^\n]", Url, 256);
	char sbuf[256] = "";
	//赋值协议
	sscanf_s(Url, "%[^:]", phu->Http, sizeof(phu->Http));
	cout << "Http = " << phu->Http << endl;
	memset(sbuf, 0, 256);
	sprintf_s(sbuf, "%s://%%[^/]", phu->Http);
	/*cout << "buf1 = " << sbuf << endl;*/
	//赋值域名
	sscanf_s(Url, (const char*)sbuf, phu->Host, sizeof(phu->Host));
	cout << "Host = " << phu->Host << endl;
	memset(sbuf, 0, 256);
	const char* sret = strchr(Url, '.');
	sret = strchr(sret, '/');
	//赋值目录
	strcpy_s(phu->Directories, sret);
	cout << "Directories = " << phu->Directories << endl;
	sret = strrchr(Url, '/');
	//赋值文件名
	strcpy_s(phu->Filename, sret + 1);
	cout << "Filename = " << phu->Filename << endl;
	memset(sbuf, 0, 256);
	//赋值端口
	for (size_t i = 0; i < strlen(phu->Directories); i++)
	{
		if (phu->Directories[i] < 0 ) {
			char hbuf[5] = "";
			memset(hbuf, 0, 5);
			memcpy_s(hbuf, 2, &phu->Directories[i], 2);
			memcpy_s(hbuf, 4, ANSIToUTF8(hbuf), 4);
			for (size_t i = 0; i < strlen(hbuf); i++)
			{
				sprintf_s(sbuf, "%s%%%hhX", sbuf, hbuf[i]);
			}
			++i;
		}
		else if(phu->Directories[i] == ' ')
		{
			sprintf_s(sbuf, "%s%%%hhX", sbuf, ' ');
		}
		else
		{
			int p = strlen(sbuf);
			sbuf[p] = phu->Directories[i];
			sbuf[p + 1] = 0;
		}
	}
	//sprintf_s(ReqHead, "GET %s HTTP/1.1\r\nConnection: close\r\n", sbuf);
	
	//赋值请求消息头
	sprintf_s(ReqHead, "GET %s HTTP/1.1\r\nConnection: Keep-alive\r\n", sbuf);
	sprintf_s(ReqHead, "%shost: %s\r\n", ReqHead, phu->Host);
	PHOSTENT HostIp;
	char* pchr = nullptr;
	char chost[64] = "";
	if (nullptr == (pchr = strchr(phu->Host, ':')))
	{
		strcpy_s(chost, phu->Host);
		if (!strcmp(phu->Http, "http"))
		{
			phu->IPPort = 80;
		}
		else if (!strcmp(phu->Http, "https"))
		{
			phu->IPPort = 443;
		}
	}
	else
	{
		int port = 0;
		sscanf_s(phu->Host, "%[^:]", chost, sizeof(chost));
		sscanf_s(pchr + 1, "%d", &port);
		phu->IPPort = port;
	}

	//域名转换IP
	HostIp = gethostbyname(chost);
	if (HostIp == NULL)
	{
		cout << "!!域名转换IP失败:[" << WSAGetLastError() << "]!!" << endl;
		Sleep(3000);
		return -102;
	}
	else {
		//地址类型
		phu->IPType = HostIp->h_addrtype;
		//IP地址
		for (int i = 0; i < 16; i++)

		{
			if (HostIp->h_addr_list[i])
			{
				strcpy_s(phu->IP[i], inet_ntoa(*(struct in_addr*)HostIp->h_addr_list[i]));
			}
			else
			{
				phu->IPnum = i;
				break;
			}
		}
		cout << "IP个数为:" << phu->IPnum << endl;
		for (int i = 0; i < phu->IPnum; i++)
		{
			printf_s("IP[%d] = %s\n", i, phu->IP[i]);
		}
		/*cout << "** 域名转换IP成功 **" << endl ;*/
	}
	return 0;
}

//创建文件映射内核对象
HANDLE FileMap(const char* FileName, DWORD FileSize) {
	//存取模式
	DWORD access_mode = (GENERIC_WRITE | GENERIC_READ);
	//共享模式
	DWORD share_mode = FILE_SHARE_READ | FILE_SHARE_WRITE;
	//文件属性
	DWORD flags = FILE_FLAG_SEQUENTIAL_SCAN;//|FILE_FLAG_WRITE_THROUGH|FILE_FLAG_NO_BUFFERING;

	//创建文件
	CreateDirectory("./Download", nullptr);

	// 创建文件对象(C: est.tsr)
	HANDLE hFile = CreateFile((LPCSTR)FileName, access_mode, share_mode, NULL, CREATE_ALWAYS, flags, NULL);
	if (hFile == INVALID_HANDLE_VALUE) {
		printf("1-创建文件失败,错误代码:%d\n\n", GetLastError());
		return NULL;
	}
	// 得到文件尺寸
	DWORD dwFileSizeHigh = 0;
	DWORD qwFileSize = GetFileSize(hFile, &dwFileSizeHigh);

	//创建文件映射对象
	HANDLE hFileMap = CreateFileMapping(hFile, NULL, PAGE_READWRITE, NULL, FileSize, nullptr);
	if (hFileMap == NULL)
	{
		printf("2-创建文件映射内核对象失败,错误代码:%d\n\n", GetLastError());
		CloseHandle(hFile);
		return NULL;
	}
	CloseHandle(hFile);

	return hFileMap;
}

//初始化请求结构体
int InitThreadMTmp(PRESPHEAD prh, PHTTPURL phu, PTHREADMTMP mtmp) {
	for (int i = 0; i < thread; i++)
	{
		mtmp[i].ThreadId = i;
		mtmp[i].DownComplete = false;
		mtmp[i].SaveComplete = false;
		mtmp[i].ThreadSize = 0;
		mtmp[i].ThreadStart = i * prh->ContentBlock;
		mtmp[i].ThreadShare = 0;
		mtmp[i].ShareBool = false;
		if (thread - 1 > i)
		{
			mtmp[i].ThreadEnd = (i + 1) * prh->ContentBlock - 1;
			mtmp[i].ThreadBlock = prh->ContentBlock;
		}
		else {
			mtmp[i].ThreadEnd = prh->ContentLength - 1;
			mtmp[i].ThreadBlock = prh->ContentLength - mtmp[i].ThreadStart;
		}
		sprintf_s(mtmp[i].ThreadName, "./Download/download-%02d.tmp",i);
		mtmp[i].FileMapTmp = FileMap(mtmp[i].ThreadName, mtmp[i].ThreadBlock);
		char path[256] = "";
		if(nullptr == _getcwd(path, 256))exit(1);
		WaitForSingleObject(hMutex, INFINITE);			//------开启互斥锁------
		if (mtmp[i].FileMapTmp == NULL) {
			printf_s("缓存文件(%s\\Download\\download-%02d.tmp)创建失败\n\n", path, i);
		}
		else
		{
			printf_s("缓存文件(%s\\Download\\download-%02d.tmp)创建完成\n\n", path, i);
		}
		ReleaseMutex(hMutex);							//------释放互斥锁------
	}
	return 0;
}

//初始SOCKET
SOCKET InitSocket(PHTTPURL phu,int h = 1, int n = -1) {
	SOCKET sockid = INVALID_SOCKET;
	int ret = 0;
	addr.sin_port = htons(phu->IPPort);
	addr.sin_addr.S_un.S_addr = inet_addr(phu->IP[h % phu->IPnum]);
	addr.sin_family = AF_INET;
	//cout << "IP:PORT = " << phu->IP[h % phu->IPnum] << ":" << phu->IPPort << endl;

	if (INVALID_SOCKET == (sockid = socket(AF_INET, SOCK_STREAM, 0)))
	{
		cout << "!! 线程[" << n << "]创建socket失败:[" << WSAGetLastError() << "] !!" << endl;
		closesocket(sockid);
		sockid = NULL;
		return INVALID_SOCKET;
	}
	else {
		//cout << "** 线程[" << n << "]创建socket成功 -- server_sockid:[" << sockid << "] **" << endl;
	}
	u_long nl = 1;
	int err = ioctlsocket(sockid, FIONBIO, &nl);						//设定SOCKET为非阻塞状态
	if (SOCKET_ERROR == err) {
		cout << "!! 设定socket非阻塞失败:WSAGetLastError["<< WSAGetLastError()<< "]  !!" << endl;
		Sleep(3000);
		exit(1);
	}
	else {
		//cout << "** 设定socket非阻塞成功 **" << endl;
	}

	while (true)
	{
		ret = connect(sockid, (SOCKADDR*)&addr, sizeof(addr));		//连接到某一个具体的服务器 
		if (ret == INVALID_SOCKET)
		{
			int errcode = WSAGetLastError();
			/*cout << "WSAGetLastError() = " << errcode << endl;*/
			if (errcode == WSAEWOULDBLOCK || errcode == WSAEINVAL|| errcode == WSAEALREADY)  //表示服务器端未预备好,继续循环  
			{
				Sleep(100);
				continue;
			}
			else
			{
				if (errcode == WSAEISCONN) //连接成功,则退出  
				{
					cout << "** 线程[" << n << "]链接服务器成功 IP = " << phu->IP[h % phu->IPnum] << " **" << endl << endl;
					break;
				}
				else                      //否则连接失败,关闭客户端套接字并释放套接字库  
				{
					printf("connect failed!");
					closesocket(sockid);
					cout << "!! 线程[" << n << "]链接服务器失败:[" << WSAGetLastError() << "] !!" << endl;
					return INVALID_SOCKET;
				}
			}
		}

	}
	
	return sockid;
}

//初始化请求消息
int InitRespHead(PRESPHEAD prh, PHTTPURL phu) {
	char* SendBuf = nullptr;
	char* RecvBuf = nullptr;
	SOCKET sockid = INVALID_SOCKET;
	FILE* ftmp = nullptr;
	int ret = 0, err = 0;
	int h = 0;
	ULONGLONG SecondsStart = GetTickCount64();		//开始时间
	ULONGLONG SecondsNow = GetTickCount64();		//现在时间
	ULONGLONG SecondsLast = GetTickCount64();		//结束时间
CreatS:
	SecondsNow = GetTickCount64();
	//发送断点下载请求
	for (int i = 0; i < phu->IPnum; i++)
	{
		if (INVALID_SOCKET != (sockid = InitSocket(phu, i+h))) {
			
			break;
		}
		else
		{
			err = WSAGetLastError();
			cout << "WSAGetLastError() = " << err << endl;
			if (i + 1 >= phu->IPnum) {
				cout << " ! ! ! 初始化“RespHead”时连接所有服务器失败 ! ! !" << endl;
				return -108;
			}
		}
	}
	SendBuf = new char[SENDBUFSIZE];
	memset(SendBuf, 0, SENDBUFSIZE);
	sprintf_s(SendBuf, SENDBUFSIZE, "%sRange: bytes=-1\r\n\r\n", ReqHead);
	/*cout << "----------------SendData2-----------------------\n" << SendBuf << "----------------end---------------------- " << endl;*/
	ret = send(sockid, SendBuf, strlen(SendBuf), 0);
	memset(SendBuf, 0, SENDBUFSIZE);
	if (SOCKET_ERROR != ret) {
		cout << "ReqHead 数据发送成功" << endl;
		delete[] SendBuf;
		SendBuf = nullptr;
	}
	else {
		err = WSAGetLastError();
		cout << "WSAGetLastError() = " << err << endl;
		cout << "ReqHead 数据发送失败" << endl;
		delete[] SendBuf;
		SendBuf = nullptr;
		return -202;
	}

	//接收断点请求应答,获取是否支持断点下载
	RecvBuf = new char[SENDBUFSIZE];
	memset(RecvBuf, 0, SENDBUFSIZE);
	while (SOCKET_ERROR == (ret = recv(sockid, RecvBuf, SENDBUFSIZE, 0)))
	{
		/*err = WSAGetLastError();
		cout << "WSAGetLastError() = " << err << endl;*/
		if (GetTickCount64() - SecondsNow >= 10000) {
			memset(RecvBuf, 0, SENDBUFSIZE);
			delete[] RecvBuf;
			RecvBuf = nullptr;
			closesocket(sockid);
			sockid = NULL;
			++h;
			Sleep(2000);
			goto CreatS;
		}

		Sleep(60);
	}
	/*cout << "----------------RecvData2-----------------------\n" << RecvBuf << endl << "----------------end---------------------- " << endl;*/
	tmpfile_s(&ftmp);
	fwrite(RecvBuf, 1, ret, ftmp);
	memset(RecvBuf, 0, SENDBUFSIZE);
	delete[] RecvBuf;
	RecvBuf = nullptr;
	rewind(ftmp);
	fscanf_s(ftmp, "%[^\r]", prh->Statusline, sizeof(prh->Statusline));
	if (!strncmp(prh->Statusline, "HTTP/1.1 206", 12)) {
		cout << "服务器持断点下载:" << prh->Statusline << endl;
		prh->Breakpoint = true;
	}
	else
	{
		cout << "服务器不支持断点下载:" << prh->Statusline << endl;
		prh->Breakpoint = false;
	}
	char  sbuf[128];
	memset(sbuf, 0, 128);
	while (0 == strcmp(prh->ContentMD5, "") || 0 == prh->ContentLength)
	{
		memset(sbuf, 0, 128);
		fscanf_s(ftmp, " %[^:\r]%*c", sbuf, 128);
		sbuf[strlen(sbuf)] = 0;
		if (!strcmp(sbuf, "Content-Range")) {
			while (fgetc(ftmp) != '/');
			fscanf_s(ftmp, "%d", &prh->ContentLength);					//获得文件总大小
			FsizeNew = 0;
			prh->ContentBlock = prh->ContentLength / thread / 65536;
			prh->ContentBlock *= 65536;									//赋值文件块大小
			cout << "文件总大小为:" << prh->ContentLength << endl;
		}
		else if (!strcmp(sbuf, "Content-MD5")) {
			fscanf_s(ftmp, "%s", prh->ContentMD5, sizeof(prh->ContentMD5));
			cout << "文件MD5为:" << prh->ContentMD5 << endl;
		}
		else if (ret <= ftell(ftmp))
			break;
	}
	
	fclose(ftmp);
	ftmp = nullptr;
	closesocket(sockid);
	sockid = NULL;
	Sleep(1000);
	return 0;
}

//HTTP普通下载
int HttpDownload(PRESPHEAD prh, PHTTPURL phu) {
	SOCKET sockid = INVALID_SOCKET;
	char* SendBuf = new char[SENDBUFSIZE];
	memset(SendBuf, 0, SENDBUFSIZE);
	char sbuf[128];
	memset(sbuf, 0, 128);
	FILE* DFile;
	int ret = 0, err = 0;
	long Fsize1 = 0, Fsize2 = 0, Ltime1 = 0, Ltime2 = 0;
	for (int i = 0; i < phu->IPnum; i++)
	{
		if (0 >= (sockid = InitSocket(phu, i))) {
			if (i + 1 == phu->IPnum) {
				cout << " ! ! ! 初始化“RespHead”时连接所有服务器失败 ! ! !" << endl;
				delete[] SendBuf;
				SendBuf = nullptr;
				return -108;
			}
		}
		else
		{
			break;
		}
	}
	sprintf_s(SendBuf, SENDBUFSIZE, "%s\r\n", ReqHead);
	cout << "----------------SendData3-----------------------\n" << SendBuf << "----------------end---------------------- " << endl;
	ret = send(sockid, SendBuf, strlen(SendBuf), 0);
	if (SOCKET_ERROR != ret) {
		cout << "ReqHead 数据发送成功" << endl;
	}
	else {
		cout << "ReqHead 数据发送失败" << endl;
		return -201;
		exit(1);
	}
	delete[] SendBuf;
	SendBuf = nullptr;
	char* RecvBuf = new char[RECVBUFSIZE];
	memset(RecvBuf, 0, RECVBUFSIZE);
	ret = recv(sockid, RecvBuf, RECVBUFSIZE, 0);
	/*cout << "----------------RecvData3:" << strlen(RecvBuf) << "-----------------------\n" << RecvBuf << endl << "----------------end---------------------- " << endl;*/
	sscanf_s(RecvBuf, "%[^\r]", sbuf, sizeof(sbuf));
	sbuf[strlen(sbuf)] = 0;
	if (0 != strncmp(sbuf, "HTTP/1.1 200 OK", 15)) {
		cout << "服务器应答报错:" << prh->Statusline << endl;
		delete[]RecvBuf;
		SendBuf = nullptr;
		closesocket(sockid);
		sockid = NULL;
		return -203;
	}
	char* pEnd = strstr(RecvBuf, "\r\n\r\n") + 4;
	CreateDirectory("./Download", nullptr);
	char fname[64];
	sprintf_s(fname, "./Download/%s", phu->Filename);
	fopen_s(&DFile, fname, "wb");
	if (NULL != DFile) {
		fwrite(pEnd, 1, ret - (int)(pEnd - RecvBuf), DFile);
		while ((ret = recv(sockid, RecvBuf, RECVBUFSIZE, 0)) > 0)
		{
			cout << ret << "-";
			Ltime2 = clock();
			if (Ltime2 - Ltime1 >= 1000) {
				cout << "下载速度:" << (Fsize2 - Fsize1) / 1024 << "KB/s,已下载:" << Fsize2 / 1024 << "KB,总大小:" << Fsize2 << " - " << prh->ContentLength << endl;
				Fsize1 = Fsize2;
				Ltime1 = Ltime2;
			}
			fwrite(RecvBuf, 1, ret, DFile);
			Fsize2 = ftell(DFile);
			if (Fsize2 >= prh->ContentLength) {
				cout << "下载速度:" << (Fsize2 - Fsize1) / 1024 << "KB/s,已下载:" << Fsize2 / 1024 << "KB,总大小:" << Fsize2 << " - " << prh->ContentLength << endl;
				break;
			}
			memset(RecvBuf, 0, RECVBUFSIZE);
		}
		
		fclose(DFile);
		DFile = nullptr;
	}
	else
	{
		cout << "创建文件失败" << endl;
	}
	delete[]RecvBuf;
	SendBuf = nullptr;
	closesocket(sockid);
	sockid = NULL;
	return 0;
}

//HTTP多线程下载
void HttpDownloadMs(PVOID Pparam) {
	PPARAM param = (PPARAM)Pparam;
	char* SendBuf = nullptr;
	char* RecvBuf = nullptr;
	long Fsize1 = 0;
	long Fsize2 = 0;
	long SStart = 0;
	DWORD BlockId = 0;
	FILE* tmp = nullptr;
	char sbuf[128] = "";
	WaitForSingleObject(hMutex, INFINITE);			//------开启互斥锁------
	int n = param->n;
	int h = n;
	++param->n;
	param->mtmp[n].DownComplete = false;
	ReleaseMutex(hMutex);							//------释放互斥锁------
	SOCKET sockid = INVALID_SOCKET;
	
	int ret = 0, err = 0;
	ULONGLONG SecondsStart = GetTickCount64();		//开始时间
	ULONGLONG SecondsNow = GetTickCount64();		//现在时间
	ULONGLONG SecondsLast = GetTickCount64();		//上一时间
	/*printf_s("Download2-ftmp%d=%p", n, param->ftmp[n].ThreadFtmp);*/
	
	tmpfile_s(&tmp);
CreatS:
	SecondsNow = GetTickCount64();
	for (int i = 0; i < param->phu->IPnum; i++)
	{
		if (INVALID_SOCKET != (sockid = InitSocket(param->phu, h + i, n))) {
			strcpy_s(param->mtmp[n].ThreadIP, param->phu->IP[(h + i) % param->phu->IPnum]);
			break;
		}
		else
		{
			err = WSAGetLastError();
			cout << "WSAGetLastError() = " << err << endl;
			if (i + 1 >= param->phu->IPnum) {
				cout << " ! ! ! 下载线程[" << n << "]时连接所有服务器失败 ! ! !" << endl;
				Sleep(3000);
				exit(1);
			}
		}
	}
	SStart = param->mtmp[n].ThreadStart + param->mtmp[n].ThreadSize;
	SendBuf = new char[SENDBUFSIZE];
	memset(SendBuf, 0, SENDBUFSIZE);
	sprintf_s(SendBuf, SENDBUFSIZE, "%sRange: bytes=%ld-%ld\r\n\r\n", ReqHead, SStart, param->mtmp[n].ThreadEnd);
	/*cout << SendBuf << endl;*/
	while (SOCKET_ERROR == (ret = send(sockid, SendBuf, strlen(SendBuf), 0)))
	{
		cout << "ReqHead 数据发送失败,重新建联" << endl;
		memset(SendBuf, 0, SENDBUFSIZE);
		delete[] SendBuf;
		SendBuf = nullptr;
		closesocket(sockid);
		sockid = NULL;
		++h;
		Sleep(2000);
		goto CreatS;
	}
	//cout << "ReqHead 数据发送成功" << endl;
	memset(SendBuf, 0, SENDBUFSIZE);
	delete[] SendBuf;
	SendBuf = nullptr;

	//接收数据
	SecondsNow = GetTickCount64();
	RecvBuf = new char[RECVBUFSIZE];
	memset(RecvBuf, 0, RECVBUFSIZE);
	while (SOCKET_ERROR == (ret = recv(sockid, RecvBuf, SENDBUFSIZE, 0)))
	{
		/*err = WSAGetLastError();*/
		if (GetTickCount64() - SecondsNow >= 10000) {
			memset(RecvBuf, 0, RECVBUFSIZE);
			delete[]RecvBuf;
			RecvBuf = nullptr;
			closesocket(sockid);
			sockid = NULL;
			++h;
			Sleep(1000);
			goto CreatS;
		}
		Sleep(60);
	}
	sscanf_s(RecvBuf, "%[^\r]", sbuf, sizeof(sbuf));
	sbuf[strlen(sbuf)] = 0;
	if (0 != strncmp(sbuf, "HTTP/1.1 206", 12)) {
		cout << "线程[" << n << "]服务器应答报错:" << sbuf << endl;
		memset(RecvBuf, 0, RECVBUFSIZE);
		delete[]RecvBuf;
		RecvBuf = nullptr;
		closesocket(sockid);
		sockid = NULL;
		Sleep(1000);
		goto CreatS;
	}
	char* pEnd = strstr(RecvBuf, "\r\n\r\n");
	if (NULL != pEnd)
	{
		pEnd += 4;
		int rsize = ret - (pEnd - RecvBuf);
		param->mtmp[n].ThreadSize += rsize;
		WaitForSingleObject(hMutex, INFINITE);			//------开启互斥锁------
		FsizeNew += rsize;
		ReleaseMutex(hMutex);							//------释放互斥锁------
		fwrite(pEnd, rsize, 1, tmp);
		Fsize2 = ftell(tmp);
		if (BLOCKSIZE  <= Fsize2)
		{
			rewind(tmp);
			fwrite(pEnd, 1, ret - (int)(pEnd - RecvBuf), tmp);
			LPVOID MemMapTmp = MapViewOfFile(param->mtmp[n].FileMapTmp, FILE_MAP_ALL_ACCESS, 0, BLOCKSIZE * BlockId++, BLOCKSIZE);
			fread_s(MemMapTmp, BLOCKSIZE, BLOCKSIZE,1 ,tmp);
			char* rbuf = new char[BLOCKSIZE];
			memset(rbuf, 0, BLOCKSIZE);
			fread_s(rbuf, Fsize2- BLOCKSIZE, Fsize2 - BLOCKSIZE, 1, tmp);
			rewind(tmp);
			fwrite(rbuf, Fsize2 - BLOCKSIZE, 1, tmp);
			delete[]rbuf;
			UnmapViewOfFile(MemMapTmp);
		}
	}
	SecondsNow = GetTickCount64();
	SecondsLast = GetTickCount64();
	Fsize1 = param->mtmp[n].ThreadSize;
	while (ret = recv(sockid, RecvBuf, RECVBUFSIZE, 0))
	{
		if (INVALID_SOCKET == ret)
		{
			err = WSAGetLastError();
			if (GetTickCount64() - SecondsNow >= 20000) {
				WaitForSingleObject(hMutex, INFINITE);			//------开启互斥锁------
				cout << "线程[" << n << "]20秒没有收到数据,重新发起连接" << endl << endl;
				ReleaseMutex(hMutex);							//------释放互斥锁------
				closesocket(sockid);
				sockid = NULL;
				++h;
				delete[]RecvBuf;
				RecvBuf = nullptr;
				Sleep(1000);
				goto CreatS;
			}
			/*cout << "WSAGetLastError() = " << err << endl;*/
			Sleep(100);
			continue;
		}
		param->mtmp[n].ThreadSize += ret;
		WaitForSingleObject(hMutex, INFINITE);			//------开启互斥锁------
		FsizeNew += ret;
		ReleaseMutex(hMutex);							//------释放互斥锁------
		SecondsNow = GetTickCount64();
		fwrite(RecvBuf, ret, 1, tmp);
		memset(RecvBuf, 0, RECVBUFSIZE);
		
		Fsize2 = ftell(tmp);
		if (BLOCKSIZE <= Fsize2)
		{
			//WaitForSingleObject(hMutex, INFINITE);			//------开启互斥锁------
			LPVOID MemMapTmp = MapViewOfFile(param->mtmp[n].FileMapTmp, FILE_MAP_ALL_ACCESS, 0, BLOCKSIZE * BlockId++, BLOCKSIZE);
			if (MemMapTmp != 0) {
				rewind(tmp);
				fread_s(MemMapTmp, BLOCKSIZE, BLOCKSIZE, 1, tmp);
				//ReleaseMutex(hMutex);							//------释放互斥锁------
				char* buf = new char[BLOCKSIZE];
				memset(buf, 0, BLOCKSIZE);
				fread_s(buf, Fsize2 - BLOCKSIZE, Fsize2 - BLOCKSIZE, 1, tmp);
				rewind(tmp);
				fwrite(buf, Fsize2 - BLOCKSIZE, 1, tmp);
				delete[]buf;
				UnmapViewOfFile(MemMapTmp);
			}
		}
		if (param->mtmp[n].ThreadSize >= (param->mtmp[n].ThreadBlock)) {
			param->mtmp[n].DownComplete = true;
			Fsize2 = ftell(tmp);
			LPVOID MemMapTmp = MapViewOfFile(param->mtmp[n].FileMapTmp, FILE_MAP_ALL_ACCESS, 0, BLOCKSIZE * BlockId++, Fsize2);
			if (MemMapTmp !=0)
			{
				rewind(tmp);
				fread_s(MemMapTmp, Fsize2, Fsize2, 1, tmp);
				UnmapViewOfFile(MemMapTmp);
			}
			fclose(tmp);
			/*if (param->MaxSpeed) {
				param->MaxSpeed = param->mtmp->ThreadBlock / (GetTickCount64() - SecondsStart);
			}*/
			WaitForSingleObject(hMutex, INFINITE);			//------开启互斥锁------
			cout << "线程" << n << "文件下载完成" << endl << endl;
			ReleaseMutex(hMutex);						//------释放互斥锁------
			closesocket(sockid);
			sockid = NULL;
			delete[]RecvBuf;
			RecvBuf = nullptr;
			break;
		}
		/*cout <mtmp[n].ThreadSize - Fsize1) / 1024 / 1024 << endl;*/
		if (GetTickCount64() - SecondsLast >= 40000) {
			SecondsLast = GetTickCount64();

			if (MaxSpeed != 0 && (float)(param->mtmp[n].ThreadSize - Fsize1) / 1024 / 1024 / 40 < MaxSpeed / 20)
			{
				WaitForSingleObject(hMutex, INFINITE);			//------开启互斥锁------
				cout << "40秒内速度" << (float)(param->mtmp[n].ThreadSize - Fsize1) / 1024 / 1024 / 40 << ",0.5MaxSpeed" << MaxSpeed / 20 << endl;
				cout << "线程[" << n << "]连续40秒下载速度低,重新发起连接" << endl << endl;
				ReleaseMutex(hMutex);							//------释放互斥锁------
				closesocket(sockid);
				sockid = NULL;
				++h;
				Sleep(2000);
				goto CreatS;
			}
			Fsize1 = param->mtmp[n].ThreadSize;
		}
		
		if (param->mtmp[n].ShareBool == true)
		{
			param->mtmp[n].ShareBool = false;
			closesocket(sockid);
			sockid = NULL;
			delete[]RecvBuf;
			RecvBuf = nullptr;
			Sleep(1000);
			goto CreatS;
		}
		/*cout << "Download2【"<< n <<"】 已下载 :"<< Fsize << endl;*/
		
	}
	
	while (true)
	{

		cout << "1分任务" << endl;
		if (param->mtmp[n].DownComplete && param->mtmp[n].SaveComplete) {
			cout << "2分任务" << endl;
			Sleep(1000);
			int num = 0;
			bool b = true;
			for (int i = 0; i < thread; i++)
			{
				WaitForSingleObject(hMutex, INFINITE);			//------开启互斥锁------
				if (i!=n && param->mtmp[i].ThreadShare < MaxShare) {
					b = false;
					ReleaseMutex(hMutex);							//------释放互斥锁------
					break;
				}
				ReleaseMutex(hMutex);							//------释放互斥锁------
			}
			if (b)
			{
				MaxShare++;
			}

			for (int i = 0; i < thread; i++)
			{
				if (i != n && param->mtmp[i].ThreadShare < MaxShare && param->mtmp[i].ThreadSize < param->mtmp[i].ThreadBlock * 8 / 10) {
					cout << "3分任务i="<mtmp[n].ThreadEnd = param->mtmp[i].ThreadEnd;
					DWORD FBlock = (param->mtmp[i].ThreadBlock + param->mtmp[i].ThreadSize) / 2 / 65536;
					param->mtmp[i].ThreadEnd = param->mtmp[i].ThreadStart + FBlock * 65536 - 1;
					param->mtmp[n].ThreadStart = param->mtmp[i].ThreadEnd + 1;
					param->mtmp[i].ThreadBlock = param->mtmp[i].ThreadEnd - param->mtmp[i].ThreadStart + 1;
					param->mtmp[n].ThreadBlock = param->mtmp[n].ThreadEnd - param->mtmp[n].ThreadStart + 1;
					
					
					ReleaseMutex(hMutex);							//------释放互斥锁------
					char path[256] = "";
					while (nullptr == _getcwd(path, 256)) {
						cout << "获取目录失败!" << endl;
					}
					while ((param->mtmp[n].FileMapTmp = FileMap(param->mtmp[n].ThreadName, param->mtmp[n].ThreadBlock)) == NULL) {
						Sleep(2000);
						printf_s("缓存文件(%s\\Download\\download-%02d.tmp)创建失败\n\n", path, i);
					}
					WaitForSingleObject(hMutex, INFINITE);			//------开启互斥锁------
					printf_s("缓存文件(%s\\Download\\download-%02d.tmp)创建完成\n\n", path, i);
					BlockId = 0;

					param->mtmp[i].ThreadShare++;
					param->mtmp[i].ShareBool = true;
					param->mtmp[n].ThreadSize = 0;
					param->mtmp[n].ThreadShare = param->mtmp[i].ThreadShare;
					param->mtmp[n].ShareBool = false;
					param->mtmp[n].DownComplete = false;
					param->mtmp[n].SaveComplete = false;
					tmpfile_s(&tmp);
					ReleaseMutex(hMutex);							//------释放互斥锁------
					goto CreatS;
				}
				else
				{
					num = i;
				}
			}
			if (num = thread-1)
			{
				break;
			}
		}
		if (param->DownComplete)
		{
			break;
		}
		Sleep(1000);
	}
	/*memset(RecvBuf, 0, RECVBUFSIZE);*/
	delete[]RecvBuf;
	RecvBuf = nullptr;
	closesocket(sockid);
	sockid = NULL;
	return;
}

//HTTPS普通下载
int HttpsDownload(PRESPHEAD prh, PHTTPURL phu) {
	SOCKET sockid = INVALID_SOCKET;
	char* SendBuf = new char[SENDBUFSIZE];
	memset(SendBuf, 0, SENDBUFSIZE);
	char sbuf[128];
	memset(sbuf, 0, 128);
	FILE* DFile;
	int ret = 0, err = 0;
	long Fsize1 = 0, Fsize2 = 0, Ltime1 = 0, Ltime2 = 0;
	for (int i = 0; i < phu->IPnum; i++)
	{
		if (0 >= (sockid = InitSocket(phu, i))) {
			if (i + 1 == phu->IPnum) {
				cout << " ! ! ! 初始化“RespHead”时连接所有服务器失败 ! ! !" << endl;
				delete[] SendBuf;
				SendBuf = nullptr;
				return -108;
			}
		}
		else
		{
			break;
		}
	}
	//初始化SSL
	//初始化OpenSSL库
	//(虽然不知道为什么,但是不加这三行似乎并不会导致什么问题,在不加这3行的情况下测试了几个网站并没有发现任何问题喵)
	SSL_library_init();					//SSL库初始化
	SSLeay_add_ssl_algorithms();		//载入所有SSL算法
	SSL_load_error_strings();			//载入所有SSL错误消息

	//创建SSL会话环境等
	SSL_CTX* pctx = SSL_CTX_new(TLS_client_method());		//产生一个SSL_CTX 数据结构
	if (pctx == NULL)
	{
		cout << "创建 SSL_CTX 失败 !!" << std::endl;
		return -1;
	}
	SSL* pssl = SSL_new(pctx);			//产生一个SLL 数据结构
	if (pssl == NULL)
	{
		std::wcout << "创建 SSL 失败 !!" << std::endl;
		return -1;
	}
	SSL_set_fd(pssl, sockid);				//将 socket 载入到 SSL 中

	bool isContinue = true;
	while (isContinue)
	{
		if (SSL_connect(pssl) == -1)
		{
			int icode = -1;
			int iret = SSL_get_error(pssl, icode);
			cout << "iret1 == " << iret << endl;
			if ((iret == SSL_ERROR_WANT_WRITE) || (iret == SSL_ERROR_WANT_READ))
			{
				isContinue = true;
			}
			/*else
			{
				SSL_CTX_free(ctx);
				SSL_free(ssl);
				ctx = NULL;
				ssl = NULL;

				break;
			}*/
		}
		else
		{
			cout << "SSL连接成功!" << endl;
			isContinue = false;
		}
	}
	cout << "ReqHead1" << ReqHead << endl;

	//初始化 get 请求头
	sprintf_s(SendBuf, SENDBUFSIZE, "%s\r\n", ReqHead);
	cout << "----------------SendData3-----------------------\n" << SendBuf << "----------------end---------------------- " << endl;
	ret = SSL_write(pssl, SendBuf, strlen(SendBuf));		//通过SSL链接发送数据
	if (SOCKET_ERROR != ret) {
		cout << "ReqHead 数据发送成功" << endl;
	}
	else {
		cout << "ReqHead 数据发送失败" << endl;
		return -201;
		exit(1);
	}
	delete[] SendBuf;
	SendBuf = nullptr;
	char* RecvBuf = new char[RECVBUFSIZE];
	memset(RecvBuf, 0, RECVBUFSIZE);
	while (true)
	{
		ret = SSL_read(pssl, RecvBuf, RECVBUFSIZE);
		if (ret > 0)
		{
			cout << "----------------RecvData3:" << strlen(RecvBuf) << "-----------------------\n" << RecvBuf << endl << "----------------end---------------------- " << endl;
			sscanf_s(RecvBuf, "%[^\r]", sbuf, sizeof(sbuf));
			sbuf[strlen(sbuf)] = 0;
			if (0 != strncmp(sbuf, "HTTP/1.1 200 OK", 15)) {
				cout << "服务器应答报错:" << prh->Statusline << endl;
				delete[]RecvBuf;
				SendBuf = nullptr;
				closesocket(sockid);
				sockid = NULL;
				return -203;
			}
			break;

		}
		
	}

	char* pEnd = nullptr;

	pEnd = strstr(RecvBuf, "Content-Length:") + 15;
	sscanf_s(pEnd,"%ld\r\n", &prh->ContentLength);
	
	
	
	pEnd = strstr(RecvBuf, "\r\n\r\n") + 4;
	CreateDirectory("./Download", nullptr);
	char fname[64];
	sprintf_s(fname, "./Download/%s", phu->Filename);
	fopen_s(&DFile, fname, "wb");
	if (NULL != DFile) {
		fwrite(pEnd, 1, ret - (int)(pEnd - RecvBuf), DFile);
		while (ret = SSL_read(pssl, RecvBuf, RECVBUFSIZE))
		{
			/*cout << ret << "-";*/
			if (ret > 0)
			{
				fwrite(RecvBuf, 1, ret, DFile);
				Fsize2 = ftell(DFile);
			}

			Ltime2 = clock();
			if (Ltime2 - Ltime1 >= 1000) {
				cout << "下载速度:" << (Fsize2 - Fsize1) / 1024 << "KB/s,已下载:" << Fsize2 / 1024 << "KB,总大小:" << Fsize2 << " - " << prh->ContentLength << "。\r";
				Fsize1 = Fsize2;
				Ltime1 = Ltime2;
			}
			/*fwrite(RecvBuf, 1, ret, DFile);
			Fsize2 = ftell(DFile);*/
			if (Fsize2 >= prh->ContentLength) {
				cout << "下载速度:" << (Fsize2 - Fsize1) / 1024 << "KB/s,已下载:" << Fsize2 / 1024 << "KB,总大小:" << Fsize2 << " - " << prh->ContentLength << endl;
				cout << "下载完成 : "<< Fsize2 << " - " << prh->ContentLength << endl;
				break;
			}
			memset(RecvBuf, 0, RECVBUFSIZE);
		}

		fclose(DFile);
		DFile = nullptr;
	}
	else
	{
		cout << "创建文件失败" << endl;
	}
	delete[]RecvBuf;
	RecvBuf = nullptr;
	SSL_shutdown(pssl);			//关闭 SSL 链接
	SSL_free(pssl);				//释放 SSL 数据结构体
	closesocket(sockid);		//释放 SOCKET
	SSL_CTX_free(pctx);			//释放 SSL_CTX 数据结构体
	return 0;

}

//HTTPS多线程下载
void HttpsDownloadMs(PVOID Pparam) {

}

//打印下载速度
void PrintMspeed(PVOID Pparam) {
	PPARAM param = (PPARAM)Pparam;
	DWORD Fsize1[16] = { 0 };
	DWORD Fsize2[16] = { 0 };
	
	long FsizeOld = 0;
	ULONGLONG SecondsStart = GetTickCount64();		//开始时间
	ULONGLONG SecondsNow = GetTickCount64();		//现在时间
	ULONGLONG SecondsSize = 0;						//运行时间
	/*DWORD Ltime1 = 0;
	DWORD Ltime2 = 0;
	DWORD Ltime = 0;*/
	float A = 0, B = 0, C = 0;
	bool b = true;
	while (true)
	{

		if (GetTickCount64() - SecondsNow >= 2000) {
			SecondsNow = GetTickCount64();
			SecondsSize = (SecondsNow - SecondsStart) / 1000;
			/*FsizeNew = 0;*/
			WaitForSingleObject(hMutex, INFINITE);			//------开启互斥锁------
			for (int i = 0; i < thread; i++)
			/*{
				FsizeNew += param->mtmp[i].ThreadSize;
			}*/
			A = (float)(FsizeNew - FsizeOld) / 1024 / 1024 / 2;
			B = (float)FsizeNew / 1024 / 1024;
			C = (float)param->prh->ContentLength / 1024 / 1024;
			SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 12);
			printf_s("下载 速度:%6.3fMB/s,已下载:%6.3fMB,总大小:%8.3fMB(bytes:%9ld-%-9ld) |(已用时间%02llu分%02I64u秒)\n", A, B, C, FsizeNew, param->prh->ContentLength, SecondsSize / 60, SecondsSize % 60);
			printf_s("最大单线速度:%6.3fMB/s,对应IP:%s\n", MaxSpeed, MaxIP);
			SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 7);
			FsizeOld = FsizeNew;
			for (int i = 0; i < thread; i++)
			{
				if (param->mtmp[i].ThreadSize < Fsize1[i])
				{
					Fsize1[i] = param->mtmp[i].ThreadSize;
				}
				A = (float)(param->mtmp[i].ThreadSize - Fsize1[i]) / 1024 / 1024 / 2;
				B = (float)param->mtmp[i].ThreadSize / 1024 / 1024;
				C = (float)param->mtmp[i].ThreadBlock / 1024 / 1024;
				SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 10);
				printf_s("线程%d[%s]速度:%6.3fMB/s,已下载:%6.3fMB,总大小:%8.3fMB(bytes:%9ld-%9ld)-(%9ld-%9ld)\n", i, param->mtmp[i].ThreadIP, A, B, C, param->mtmp[i].ThreadSize, param->mtmp[i].ThreadBlock, param->mtmp[i].ThreadStart, param->mtmp[i].ThreadEnd);
				SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 7);
				Fsize1[i] = param->mtmp[i].ThreadSize;
				if (A > MaxSpeed ) {
					if (MaxSpeed == 0)
					{
						MaxSpeed = A;
						strcpy_s(MaxIP, param->mtmp[i].ThreadIP);
					}
					else if (A / MaxSpeed < 3)
					{
						MaxSpeed = A;
						strcpy_s(MaxIP, param->mtmp[i].ThreadIP);
					}
				}
			}
			cout << endl;
			ReleaseMutex(hMutex);							//------释放互斥锁------

		}
		b = true;
		for (int i = 0; i < thread; i++)
		{
			if (!param->mtmp[i].DownComplete) {
				b = param->mtmp[i].DownComplete;
				break;
			}
		}
		if (b) {
			param->DownComplete = true;
			WaitForSingleObject(hMutex, INFINITE);			//------开启互斥锁------
			FsizeNew = param->prh->ContentLength;
			A = (float)(FsizeNew - FsizeOld) / 1024 / 1024 / (GetTickCount64() - SecondsNow) * 1000;
			B = (float)param->prh->ContentLength / 1024 / 1024;
			C = (float)param->prh->ContentLength / 1024 / 1024;
			SecondsSize = (GetTickCount64() - SecondsStart) / 1000;
			SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 12);
			printf_s("下载 速度:%6.3fMB/s,已下载:%6.3fMB,总大小:%8.3fMB(bytes:%9ld-%-9ld) |(已用时间%02llu分%02I64u秒)\n", A, B, C, param->prh->ContentLength, param->prh->ContentLength, SecondsSize / 60, SecondsSize % 60);
			printf_s("最大单线速度:%6.3fMB/s,对应IP:%s\n", MaxSpeed, MaxIP);
			SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 7);
			for (int i = 0; i < thread; i++) {
				Fsize2[i] = param->mtmp[i].ThreadSize;
				A = (float)(param->mtmp[i].ThreadSize - Fsize1[i]) / 1024 / 1024 / (GetTickCount64() - SecondsNow) * 1000;
				B = (float)param->mtmp[i].ThreadBlock / 1024 / 1024;
				C = B;
				SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 10);
				printf_s("线程%d[%s]速度:%6.3fMB/s,已下载:%6.3fMB,总大小:%8.3fMB(bytes:%9ld-%-9ld)\n", i, param->mtmp[i].ThreadIP, A, B, C, param->mtmp[i].ThreadBlock, param->mtmp[i].ThreadBlock);
				SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 7);
			}
			cout << endl;
			ReleaseMutex(hMutex);							//------释放互斥锁------
			SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 12);
			cout << "\n\n* * * 文件下载完成,数据保存中,请等待..... * * *\n" << endl;
			SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 7);
			break;
		}else
		Sleep(100);
		/*if (0 != errq)
		{
			break;
		}*/
	}
	return;
}

//保存输出文件
int Create_MFile(PRESPHEAD prh, PHTTPURL phu, THREADMTMP mtmp[16]) {
	bool b = true;
	char tname[128];
	sprintf_s(tname, "./Download/%s.tmp", phu->Filename);
	HANDLE DFileMap = FileMap(tname, prh->ContentLength);
	char path[128] = "";
	if (nullptr == _getcwd(path, 128))exit(1);
	WaitForSingleObject(hMutex, INFINITE);			//------开启互斥锁------
	if (DFileMap == NULL)
	{
		printf_s("预备文件(%s\\Download\\%s.tmp)创建失败\n\n", path, phu->Filename);
	}
	else
	{
		printf_s("预备文件(%s\\Download\\%s.tmp)创建完成\n\n", path, phu->Filename);
	}
	ReleaseMutex(hMutex);							//------释放互斥锁------
	while (true)
	{
		for (int i = 0; i < thread; i++)
		{
			/*cout << i << "-保存文件-" << mtmp[i].DownComplete <<"-|-"<< mtmp[i].SaveComplete << endl;*/
			if (mtmp[i].DownComplete && !mtmp[i].SaveComplete)
			{
				
				Sleep(1000);
				DWORD BlockId = 0;
				WaitForSingleObject(hMutex, INFINITE);			//------开启互斥锁------
				for (DWORD BlockId = 0;BlockId* BLOCKSIZE < mtmp[i].ThreadBlock; BlockId++)
				{
					if ((BlockId+1) * BLOCKSIZE > mtmp[i].ThreadBlock)
					{
						LPVOID MemMapTmp = MapViewOfFile(mtmp[i].FileMapTmp, FILE_MAP_ALL_ACCESS, 0, BLOCKSIZE * BlockId, 0);
						LPVOID DMemMap = MapViewOfFile(DFileMap, FILE_MAP_ALL_ACCESS, 0, mtmp[i].ThreadStart + BLOCKSIZE * BlockId, 0);
						if (MemMapTmp != 0 && DMemMap != 0)
						{
							memcpy_s((PCHAR)DMemMap, mtmp[i].ThreadBlock - BlockId * BLOCKSIZE, MemMapTmp, mtmp[i].ThreadBlock - BlockId * BLOCKSIZE);
							UnmapViewOfFile(MemMapTmp);
							UnmapViewOfFile(DMemMap);
						}
					}
					else
					{
						LPVOID MemMapTmp = MapViewOfFile(mtmp[i].FileMapTmp, FILE_MAP_ALL_ACCESS, 0, BLOCKSIZE * BlockId, 0);
						LPVOID DMemMap = MapViewOfFile(DFileMap, FILE_MAP_ALL_ACCESS, 0, mtmp[i].ThreadStart + BLOCKSIZE * BlockId, 0);
						if (MemMapTmp !=0 && DMemMap != 0)
						{
							memcpy_s((PCHAR)DMemMap, BLOCKSIZE, MemMapTmp, BLOCKSIZE);
							UnmapViewOfFile(MemMapTmp);
							UnmapViewOfFile(DMemMap);
						}
					}
				}
				CloseHandle(mtmp[i].FileMapTmp);
				DeleteFile((LPCSTR)mtmp[i].ThreadName);
				mtmp[i].SaveComplete = true;
				cout << "线程" << i << "缓存文件已写入预备文件完并删除缓存文件。" << endl << endl;
				ReleaseMutex(hMutex);							//------释放互斥锁------
			}
		}
		b = true;
		for (int i = 0; i < thread; i++) {
			b = b && mtmp[i].SaveComplete;
			if (!b) {
				break;
			}
		}
		if (b) {
			CloseHandle(DFileMap);
			/*if (0 != DFileMap)
			{
				CloseHandle(DFileMap);
			}*/
			break;
		}
		Sleep(200);
	}
	cout << "所有缓存文件已写入预备文件" << endl << endl;
	char fname[128];
	sprintf_s(fname, "./Download/%s", phu->Filename);
	FILE* pf;
	fopen_s(&pf, fname, "r");
	if (nullptr != pf)
	{
		fclose(pf);
		char fbak[128] = "";
		sprintf_s(fbak, "%s.bak", fname);
		if (0 == rename(fname, fbak)) {
			cout << "文件已存在,已备份为:" << endl;
			printf_s("%s\\Download\\%s.bak\n", path, phu->Filename);
		}
		else
		{
			remove(fname);
			cout << "文件已存在,备份失败,已被直接删除!!" << endl;
		}
	}
	if (0 == rename(tname,fname)) 
	{
		printf("预备文件转换成正式文件完成,文件位置:\n");
		printf_s(" %s\\Download\\%s\n", path, phu->Filename);
	}
	else
	{
		printf("重命名失败,请手动删除[%s\\Download\\%s.tmp]后的【.tmp】\n", path, phu->Filename);
	}
	
	cout << "\n* * * 文件下载结束 * * *" << endl;
	SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 7);
	return 0;
}

4.  main.cpp

#include"global.h"
HANDLE hMutex = CreateMutex(NULL, FALSE, "trw");		//创建互斥句柄,命名为“trw”
int errq = 0;
WSADATA WsaData;
int thread = 16;
float MaxSpeed = 0;
char MaxIP[16] = "";
int InitHttpurl(PHTTPURL phurl);								//初始化URL结构体
int InitRespHead(PRESPHEAD prh, PHTTPURL phu);					//初始化请求结构体
int InitThreadMTmp(PRESPHEAD prh, PHTTPURL phu, PTHREADMTMP mtmp); //初始化M线程结构体
int HttpDownload(PRESPHEAD prh, PHTTPURL phu);						//http普通下载
int HttpsDownload(PRESPHEAD prh, PHTTPURL phu);						//https普通下载
void HttpDownloadMs(PVOID Pparam);									//多线程M下载
void PrintMspeed(PVOID Pparam);									//打印M下载速度
int Create_MFile(PRESPHEAD prh, PHTTPURL phu, THREADMTMP mtmp[16]);	//保存M文件


int main() {
	/*system("mode con cols=100 lines=100");*/
	HTTPURL HttpUil = { 0 };							//定义URL结构体
	//THREADTMP FileTmp[16];								//定义线程缓存文件
	THREADMTMP MTmp[16];								//定义线程缓存文件
	RESPHEAD RespHead ;									//定义请求消息结构体
	PARAM SParam = { NULL };							//定义线程参数结构第
	int S = 14, T = 10;									//定义打印变量
	SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), T);
	printf_s("┌────────────────────────────────────────────────┐\n");
	printf_s("%-50s%s\n%-7s", "│", "│", "│");
	SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), S);
	printf_s("%-43s", "作    者:仝 (TRW666)");
	SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), T);
	printf_s("%s\n%-50s%s\n%-7s", "│", "│", "│", "│");
	SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), S);
	printf_s("%-43s", "博客地址:https://blog.csdn.net/trw777");
	SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), T);
	printf_s("%s\n%-50s%s\n", "│", "│", "│");
	printf_s("└────────────────────────────────────────────────┘\n");
	SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 7);

	WSADATA WsaData;

	//初始换SOCKET绑定库
	if (0 != WSAStartup(MAKEWORD(2, 2), &WsaData)) {
		cout << "!!初始化socket库文件失败:[" << WSAGetLastError() << "]!!" << endl;
		Sleep(3000);
		return SOCKET_ERROR;
	}

	//运行始化URL函数
	if (0 != (errq = InitHttpurl(&HttpUil))) {
		cout << "错误码:ERR = " << errq << endl;
		system("pause");
		return errq;
	}
	
	//线程数赋值
	if (TNUM * HttpUil.IPnum < 16)
	{
		thread = TNUM * HttpUil.IPnum;
	}
	else {
		thread =16 ;
	}
	//thread = 1;
	cout <<"线程个数为:" << thread << endl;
	Sleep(1000);

	if (!strcmp(HttpUil.Http,"https"))
	{
		HttpsDownload(&RespHead, &HttpUil);							//执行普通下载
		return 0;
	}

	//运行初始化请求消息函数
	if (0 != (errq = InitRespHead(&RespHead, &HttpUil))) {
		cout << "错误码:ERR = " << errq << endl;
		system("pause");
		return errq;
	}

	//判断是否支持断点下载并执行
	if (RespHead.Breakpoint&& RespHead.ContentBlock)
	{
		InitThreadMTmp(&RespHead,&HttpUil,MTmp);
		SParam.phu = &HttpUil;
		SParam.prh = &RespHead;
		SParam.ftmp = nullptr;
		SParam.mtmp = MTmp;
		SParam.n = 0;
		_beginthread(PrintMspeed, 0, (PVOID)&SParam);			//执行打印速度
		for (int i = 0; i < thread; i++)
		{
			_beginthread(HttpDownloadMs, 0, (PVOID)&SParam);			//执行多线程下载
			while (SParam.n == i){
				Sleep(100);
			}
		}
		
		Sleep(2000);
		Create_MFile(&RespHead ,&HttpUil, MTmp);				//执行保存文件
	}
	else
	{
		HttpDownload(&RespHead, &HttpUil);							//执行普通下载
	}
	WSACleanup();
	if (0 != errq)
	{
		cout << "错误码:ERR = " << errq << endl;
	}
	system("pause");
	return errq;
}

你可能感兴趣的:(C/C++,http,服务器,网络协议)