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

第二季主要修改功能:https://blog.csdn.net/trw777/article/details/104544824

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

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

本季主要修改功能:

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

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

代码组成部分分为:头文件--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 2
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 (0 < (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 (0 < 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 (0 < 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 (0 < 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>#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;
}//普通下载
int Download(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;
}//多线程下载
void DownloadMs(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;
}//打印下载速度
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(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 Download(PRESPHEAD prh, PHTTPURL phu);                      //普通下载
void DownloadMs(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 (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(DownloadMs, 0, (PVOID)&SParam);         //执行多线程下载while (SParam.n == i){Sleep(100);}}Sleep(2000);Create_MFile(&RespHead ,&HttpUil, MTmp);              //执行保存文件}else{Download(&RespHead, &HttpUil);                            //执行普通下载}WSACleanup();if (0 != errq){cout << "错误码:ERR = " << errq << endl;}system("pause");return errq;
}

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

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

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

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

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

  3. 一个微信小程序下载保存视频的模块,支持进度显示

    封装好的代码,代码量很少但调用很方便,有完整的事件监听,将它保存为 saveFileUtil.js 其实代码还是偷懒了,比如 wx.downloadFile 里面只有 success 监听,没有 fa ...

  4. 微信小程序 开发工具 项目创建步骤

    账号申请 后台小程序信息完善 安装开发工具IDE 小程序项目搭建 项目编译 真机预览调试 小程序开发前准备: ①申请账号 ②安装开发工具 账号申请 进入小程序注册页 根据指引填写信息和提交相应的资料, ...

  5. 使用易语言搭建WEB服务器且支持大文件下载/断点传输

    易语言搭建WEB服务器,无非就是对数据处理与协议头分析做得好即可,扩展插件也不难,只需要接入相应接口即可,那么这次也是直接使用WINDOWS API的socket套接字进行搭建的WEB服务器. 目前尚 ...

  6. 猜画小歌小程序辅助工具

    一.项目简介 猜画小歌小程序辅助工具 二.实现功能 支持绘制直线 支持绘制圆形 支持绘制椭圆形 支持绘制矩形 支持绘制三角形 支持绘制连续线段 支持绘制二阶贝塞尔曲线 支持绘制三阶贝塞尔曲线 三.技术 ...

  7. c语言 串口 封装,首颗超小封装的串口(UART)转PWM转换芯片ZWI10A

    全球首颗超小封装的串口(UART)转PWM控制芯片SOC. 功能概述 ● PWM输出特性 - PWM输出范围150HZ-200KHZ. - PWM频率为16位精度. -占空比调节方式(0-255). ...

  8. 【牛客刷题】上手用C语言写一个三子棋小游戏超详解哦(电脑优化)

    作者:[南航科院小张 南航科院小张的博客 专栏:从c语言的入门到进阶 学习知识不只是要懂,还要会用:想要找到好的工作,这里给大家介绍一件可以斩获诸多大厂offer的利器–牛客网 点击免费注册和我一起开 ...

  9. c语言定二维义数组,C语言二维数组超细讲解

    用一维数组处理二维表格,实际是可行的,但是会很复杂,特别是遇到二维表格的输入.处理和输出. 在你绞尽脑汁的时候,二维数组(一维数组的大哥)像电视剧里救美的英雄一样显现在你的面前,初识数组的朋友们还等什 ...

最新文章

  1. 深入jQuery中的data()
  2. 当当大促的额外优惠来啦!160 买 400的书!搓搓搓~
  3. 让 Git 全局性的忽略 .DS_Store
  4. 计算机网络第四章-网络层复习笔记
  5. 【简单解法】1093 字符串A+B (20分)_16行代码AC
  6. My97 DatePicker获取自定义日期的前一天
  7. 尝试:Script Lab,开发模式之知识储备//SL02
  8. 机器学习实战 | 数据探索(变量变换、生成)
  9. MongoDB学习笔记~以匿名对象做为查询参数,方便查询子对象
  10. aspen和python一起使用_python-将$cond语句与$project一起使用并在PyMongo中聚合
  11. Online Judge for ACM-ICPC etc.
  12. SQL Server-【知识与实战V】视图
  13. ubuntu安装python和pycharm_在Ubuntu 20.04中安装Pycharm 2020.1的图文教程
  14. 下载各种百度文库以及豆丁网文章的简便方法
  15. vs2013下载安装
  16. 若w=1,x=2,y=3,z=4,则条件表达式wx?w : zy?z : x的结果为 4
  17. 【Hexo搭建个人博客】:yilia主题配置(二) - 背景图片
  18. 信息收集-CDN绕过
  19. SOCK_NONBLOCK,accept4 阻塞与非阻塞SOCKET
  20. 【论文翻译】Clustering by fast search and find of density peaks

热门文章

  1. 隐私保护,在法规以外更依赖技术
  2. netCMS学习笔记
  3. 饿了么三面:让你怀疑人生的Spring Boot夺命连环40问
  4. Java 日期和时间
  5. 行亦谦ACM自闭之旅第三周
  6. [附源码]计算机毕业设计JAVA水果商城
  7. 计算机联机玩游戏的操作方法,笔记本电脑Windows7 如何联机玩游戏?
  8. \\老老实实用百度博客吧,HOHO、
  9. Java--获取属性(System.getProperty)--方法/实例
  10. SimCoat自动喷涂机操作手册