第一季简单实现了下载功能: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<stdio.h>                     //输入输出-文件
#include<iostream>                        //C++输入输出-文件
#include<WinSock2.h>                  //SOCKET网络连接
#include<process.h>                       //多线程头文件
#include<synchapi.h>                  //互斥锁头文件,可不添加从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] = { "" };            //文本IPint    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;                    //线程IDchar 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;                   //线程IDchar 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 <stdio.h>
#include <windows.h>
#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<stdlib.h>
#include<WS2tcpip.h>
#include <windows.h>
#include<direct.h>
#include <time.h>
#include<openssl\ssl.h>
#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;}//域名转换IPHostIp = 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 <<n <<"-SJC:" << GetTickCount64() - SecondsLast <<" |ZDSD:"<< MaxSpeed * 4/10 <<" |SJSD"<<(float)(param->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="<<i << endl;WaitForSingleObject(hMutex, INFINITE);            //------开启互斥锁------param->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);      //释放 SOCKETSSL_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;}elseSleep(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 语言 GET请求 超小纯净下载工具 (支持http、https)第四季相关推荐

  1. C 语言http GET请求 超小纯净下载工具 (暂时只支持http)第二季

    第一季简单实现了下载功能:https://blog.csdn.net/trw777/article/details/104459563 本次主要更新断点多线程断点下载功能: 1.域名有几个IP,建几个 ...

  2. C 语言http GET请求 超小纯净下载工具 (暂时只支持http,支持大文件下载)第三季

    第一季简单实现了下载功能:https://blog.csdn.net/trw777/article/details/104459563 第二季主要修改功能:https://blog.csdn.net/ ...

  3. 袋鼠下载IOS用的一款不限速下载工具支持极速下载,在线秒播

    袋鼠下载是一款iOS端的下载类应用,支持下载敏感资源,下载速度高达100M/S,支持磁力种子电驴迅雷链接,云端秒播,在线观看 支持投屏及倍速播放,欢迎各位老司机下载体验 特点:整个下载界面非常的干净整 ...

  4. Folx Pro5下载器堪比IDM的下载工具 支持下载磁力链接和种子文件

    Folx Pro是Mac系统上一款媲美IDM的,不对,它还支持下载磁力链接和种子文件,可以说是十分强大的下载工具! Folx是一款免费的macOS专用的下载器,完全Mac风格的用户界面.提供便捷的下载 ...

  5. 家庭财务小管家c语言程序,家庭理财小管家下载

          家庭理财小管家官方版是一款非常实用的家庭财务管理软件,家庭理财小管家官方版能够帮助用户轻松管理家庭中的日常开销数据,从而让用户更有规划性地进行消费.家庭理财小管家官方版能够让用户培养自己的 ...

  6. c语言魔塔编程,魔塔V1.0 用C语言写的魔塔小游戏 - 下载 - 搜珍网

    压缩包 : dcd725aa21879836d2b9168396fe6e.zip 列表 audio/ audio/ATACK.wav audio/BUY.wav audio/EXCHANGE.wav ...

  7. 配置小程序开发者工具及其使用(上)

    本章主要介绍: 如何配置小程序开发工具 开发工具的基本操作使用 如何创建小程序项目和调试代码 如何配置小程序开发工具 配置小程序开发工具是开始进行小程序开发的重要步骤.下面是一个简要的配置指南: 下载 ...

  8. 【PC工具】更新github下载加速器,github项目辅助下载工具,github高速下载

    之前分享过的两个github下载加速器最近发现不能用了,今天更新一下,之前的内容还有一些参考价值就不删了. 功能:顾名思义github下载加速器,因为很多原因和你懂的原因,github上下载速度有时是 ...

  9. 【PC工具】github项目辅助下载工具,github高速下载

    今天再来聊聊这个神奇的未来网站:github,没错就是那个"全球最大的同性交友网站"(这是个笑话不用当真,只是暗指程序员工程师都很喜欢来这).用过的朋友都知道,下载速度有点感人,今 ...

最新文章

  1. java正则表达式练习题目
  2. 《jQuery Mobile入门经典》—— 2.7 练习
  3. qunee for html5 api,Qunee for HTML5 - 中文 : 常见问题
  4. java safevarargs_@SafeVarargs注解的使用
  5. 201506251117_《react——所需知识、主要技术》
  6. MySQL调优(三):索引基本实现原理及索引优化,哈希索引 / 组合索引 / 簇族索引等
  7. IT:如何使用Server 2008 R2上的远程桌面服务设置自己的终端服务器
  8. 将ONNX对象检测模型转换为iOS Core ML(一)
  9. 使用BI软件的好处有哪些
  10. 区块链 Hyperledger fabric 排序服务Kafka
  11. 每日一句090516
  12. 电脑管家下载|腾讯电脑管家下载
  13. 安装VMware tools好处
  14. Stata异方差的修正
  15. 利用标准差剔除异常数据
  16. Context与ContextImpl
  17. 【NGINX】nginx+uwsgi+django+python部署总结
  18. SVN mac 破解版
  19. 计算机专业基础综合408备考经验分享
  20. php 直接上传到七牛云,七牛云存储-如何使用php上传大文件到七牛云储?

热门文章

  1. 安全框架Shiro的简单学习
  2. 1. 写一个基本的类
  3. 泊松分布分析足球比赛
  4. 使用Navicat迁移MySQL数据至Oracle时大小写原因报“表或视图不存在”问题处理
  5. VIM配置攻略 YouCompleteMe---自动补全插件安装攻略
  6. PCB板设计阻抗匹配和零欧姆电阻作用解析
  7. 一本不错的书《软件项目管理》,有感(一)
  8. 刚刚!教育部公示:这些高校,更名大学!
  9. 微软VS苹果 桌面操作系统的终极一战
  10. web,h5海康视频接入监控视频流记录一