第一季简单实现了下载功能: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)
#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;
#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));
}
#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;
}
#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;
}