⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 httpdownload.cpp

📁 模拟迅雷的下载工具软件
💻 CPP
📖 第 1 页 / 共 3 页
字号:
// HttpDownLoad.cpp : implementation file
//

#include "stdafx.h"
#include "LeoBlock2004.h"
#include "HttpDownLoad.h"

#include "winsock2.h"
#include "afxinet.h"
#include "HttpSocket.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CHttpDownLoad


UINT TestSocketLink(void *lParam); //测试Socket是否连接成功
//UINT StartHttpDownLoad(void *lParam);
UINT DownLoad(void *lParam);       //下载文件的核心子线程!!!
void CalueFloat(CString &f1,CString &b2,CString ss);  //float 123.46=sz=123,sz2=46
void CalueSpareTimer(long &hh,long &mm,long &ss,long lComp,long lbps);
void CalueTimertoSZ(int ihh,int imm,int iss,char sz[]);
void CalueName(CString &f1,CString &b2,CString ss);

UINT DownLoad(void *lParam)
{

	//=================Define Main Info============================
	LEODOWN_INFO* LeoDownInfo=(LEODOWN_INFO*)lParam;
	CWnd *pMainFrame=(CWnd*)LeoDownInfo->pMainFrame;
	CHttpDownLoad *pHttpDL=(CHttpDownLoad*)LeoDownInfo->the;
	
	HKEY nhKeyRoot=HKEY_CURRENT_USER;
	CLRegistry DownRegistry;
	//=============================================================
	
	
	//=======================Socket Define Type=====================
	
	CString strServer,strObject;
	DWORD dwServiceType;
	DWORD dwStartTime,dwEndTime,dwTime;
	BOOL  bIsStartTime=FALSE;
	const char *pRequestHeader = NULL;
	char *pResponseHeader=NULL;
	char *pAcceptType=NULL;
	unsigned short nPort;
	int nTimeout=pHttpDL->m_stLeoDownInfo.stSocketType.nTimeOut;
	long nLength;
	long lRevLength=0;
	long lSizeLength=1024;
	int  nSocketLinkNum=1;
	long nCompletedSize = LeoDownInfo->lBreakPointByte;  //开始的字节数
	long nFileSize=LeoDownInfo->lToByte;                 //结束的字节数
	long CompleOffset=nCompletedSize;                    //nBreakRev=1 "Percent" -Compleoffet
	int  nBreakRev=LeoDownInfo->nBreakRev;

	CString strFileName=LeoDownInfo->strFilePath;
	LPCTSTR strLocatea=(LPCTSTR)LeoDownInfo->strLocationUrl;
	CString sRegPath=LeoDownInfo->strRegSubPath;
	int nPID=LeoDownInfo->nPID;
	int nCID=LeoDownInfo->nCID;
	pHttpDL->m_stHttpDlInfo.lFileLength=LeoDownInfo->lFileLength;
	pHttpDL->m_stHttpDlInfo.strRegPath=sRegPath;
	if(nCID==0)
	{
		pHttpDL->m_stHttpDlInfo.BreakInfo0.nCID=LeoDownInfo->nCID;
		pHttpDL->m_stHttpDlInfo.BreakInfo0.lFromeByte=nCompletedSize;
		pHttpDL->m_stHttpDlInfo.BreakInfo0.lToByte=nFileSize;
	}
	else if(nCID==1)
	{
		pHttpDL->m_stHttpDlInfo.BreakInfo1.nCID=LeoDownInfo->nCID;
		pHttpDL->m_stHttpDlInfo.BreakInfo1.lFromeByte=nCompletedSize;
		pHttpDL->m_stHttpDlInfo.BreakInfo1.lToByte=nFileSize;
	}
	else if(nCID==2)
	{
		pHttpDL->m_stHttpDlInfo.BreakInfo2.nCID=LeoDownInfo->nCID;
		pHttpDL->m_stHttpDlInfo.BreakInfo2.lFromeByte=nCompletedSize;
		pHttpDL->m_stHttpDlInfo.BreakInfo2.lToByte=nFileSize;
	}
	else if(nCID==3)
	{
		pHttpDL->m_stHttpDlInfo.BreakInfo3.nCID=LeoDownInfo->nCID;
		pHttpDL->m_stHttpDlInfo.BreakInfo3.lFromeByte=nCompletedSize;
		pHttpDL->m_stHttpDlInfo.BreakInfo3.lToByte=nFileSize;
	}
	else if(nCID==4)
	{
		pHttpDL->m_stHttpDlInfo.BreakInfo4.nCID=LeoDownInfo->nCID;
		pHttpDL->m_stHttpDlInfo.BreakInfo4.lFromeByte=nCompletedSize;
		pHttpDL->m_stHttpDlInfo.BreakInfo4.lToByte=nFileSize;
	}
	//===============================================================
	
	DownRegistry.Open(nhKeyRoot,sRegPath);
	CString sTemp,sTemp1;

	CFile DownloadFile; //打开在StartHttpDownLoad()中创建的文件
	DownloadFile.Open((LPCTSTR)strFileName,CFile::modeWrite|CFile::shareDenyNone);

	//while(TRUE)
	while(nCompletedSize < nFileSize && nSocketLinkNum<=LeoDownInfo->nSocketLinkNum)
	{
		nSocketLinkNum++;
		AfxParseURL(strLocatea,dwServiceType,strServer,strObject,nPort);  //分解网址
		//http://www.xxx.xxx/xx/xxx/x.zip
		//strServer=www.xxx.xxx,strObject=/xx/xxx/x.zip,nPort=端口
		CHttpSocket HttpSocket;
		//开始格式化Socket头
		pRequestHeader = HttpSocket.FormatRequestHeader((LPTSTR)(LPCTSTR)strServer,(LPTSTR)(LPCTSTR)strObject,nLength,NULL,NULL,nCompletedSize,nFileSize,0,NULL);	
		HttpSocket.CloseSocket();                              //关闭Socket,防止以前打开过
		HttpSocket.Socket();                                   //初始化Socket
		HttpSocket.Connect((LPTSTR)(LPCTSTR)strServer,nPort);  //连接Socket
		HttpSocket.SendRequest();                              //向服务器发送请求信息
		HttpSocket.SetTimeout(nTimeout,0);                     //设置连接超时
		pResponseHeader=HttpSocket.GetResponseCharPoint();     //返回服务器的回应信息

		int nSvrState = HttpSocket.GetServerState();           //获得服务器的状态值
		LeoDownInfo->nSvrState=nSvrState;
		CString csState;
		csState.Format("%d",nSvrState);
		csState=csState.Left(1);
		if(csState=="2")
		{
			//连接成功,向列表控件发送服务器回应信息
			int nLineSize = 0;
			char szLine[256];
			while(nLineSize != -1)
			{
				nLineSize = HttpSocket.GetResponseLine(szLine,256);
				if(nLineSize > -1)
				{
					szLine[nLineSize] = '\0';
					::SendMessage(pMainFrame->m_hWnd,WM_TESTLIST,0,(LPARAM)szLine);
				}
			}			

			//以下if语句用于判断子线程是否下载完毕(请看StartHttpDownLoad()中的"注意1"后面的语句)
			if(nCID==0)
			{
				pHttpDL->m_stHttpDlInfo.BreakInfo0.bRevData0=TRUE;
			}
			else if(nCID==1)
			{
				pHttpDL->m_stHttpDlInfo.BreakInfo1.bRevData1=TRUE;
			}
			else if(nCID==2)
			{
				pHttpDL->m_stHttpDlInfo.BreakInfo2.bRevData2=TRUE;
			}
			else if(nCID==3)
			{
				pHttpDL->m_stHttpDlInfo.BreakInfo3.bRevData3=TRUE;
			}
			else if(nCID==4)
			{
				pHttpDL->m_stHttpDlInfo.BreakInfo4.bRevData4=TRUE;
			}
			//File Seek to per thread begin byte
			
			char pData[1024];    //用于存放接收数据的字符数组
			long nReceSize = 0;  //实际接收数据的长度(服务器返回来的值)
			if(!bIsStartTime)
			{
				dwStartTime = GetTickCount();  //1:用于下载速率
				bIsStartTime=TRUE;             //2:用于下载速率
			}

			DownloadFile.Seek(LeoDownInfo->lBreakPointByte,CFile::begin);  //设置文件指针位置
			while(nCompletedSize <= nFileSize)
			{
				nReceSize = HttpSocket.Receive(pData,1024);   //!!!开始从服务器接收数据
				dwEndTime = GetTickCount();                   //3:用于下载速率
				if(nReceSize<=0)
				{
					HttpSocket.CloseSocket();                 //没有可以接收的数据,关闭Socket      
					break;                                    //return while(TRUE)  !!!
				}
				DownloadFile.Write(pData,nReceSize);          //如果接收成功,开始向文件当前位置写入数据
				nCompletedSize += nReceSize;                  //累计已经下载的数据(用于判断是否等于要下载文件的长度,如果等于证明下载结束)
				lRevLength+=nReceSize;						  //4:用于下载速率
				LeoDownInfo->lBreakPointByte=nCompletedSize;  //!!!保存此子线程已经下载的字节数(用于下次下载的开始位置)

				//5:用于下载速率
				dwTime=dwEndTime-dwStartTime;
				if(dwTime==0)
					dwTime=10;
				float fSpeed = 0.0f;
				fSpeed=(float)lRevLength;
				fSpeed = fSpeed/(((float)dwTime)/1000.0f);
				LeoDownInfo->fSpeed=fSpeed;
				//6:用于下载速率,存入当前的子线程中
				if(nCID==0)
				{
					pHttpDL->m_stHttpDlInfo.BreakInfo0.BreakLength0=LeoDownInfo->lBreakPointByte;
					pHttpDL->m_stHttpDlInfo.BreakInfo0.lSpeed0=fSpeed;

				}
				else if(nCID==1)
				{
					pHttpDL->m_stHttpDlInfo.BreakInfo1.BreakLength1=LeoDownInfo->lBreakPointByte;
					pHttpDL->m_stHttpDlInfo.BreakInfo1.lSpeed1=fSpeed;
				}
				else if(nCID==2)
				{
					pHttpDL->m_stHttpDlInfo.BreakInfo2.BreakLength2=LeoDownInfo->lBreakPointByte;
					pHttpDL->m_stHttpDlInfo.BreakInfo2.lSpeed2=fSpeed;
				}
				else if(nCID==3)
				{
					pHttpDL->m_stHttpDlInfo.BreakInfo3.BreakLength3=LeoDownInfo->lBreakPointByte;
					pHttpDL->m_stHttpDlInfo.BreakInfo3.lSpeed3=fSpeed;

				}
				else if(nCID==4)
				{
					pHttpDL->m_stHttpDlInfo.BreakInfo4.BreakLength4=LeoDownInfo->lBreakPointByte;
					pHttpDL->m_stHttpDlInfo.BreakInfo4.lSpeed4=fSpeed;
				}
				//写入注册表中的数据 {BreakLength?,ToLength?,bps/s}
				//"Software\\BLeo2004\\DownLoad\\Down?";
				sTemp="";
				sTemp1="";
				sTemp.Format("%ld",LeoDownInfo->lBreakPointByte);
				sTemp1.Format("BreakLength%d",nCID);
				DownRegistry.Write((LPCTSTR)sTemp1,(LPCTSTR)sTemp);
				
				sTemp.Empty();
				sTemp1.Empty();
				sTemp.Format("%ld",LeoDownInfo->lToByte);
				sTemp1.Format("ToLength%d",nCID);
				DownRegistry.Write((LPCTSTR)sTemp1,(LPCTSTR)sTemp);
				
				sTemp1.Empty();
				sTemp.Empty();
				if(nCID==0)
				{
					sTemp.Format("%.0f",fSpeed);
					DownRegistry.Write("bps0",(LPCTSTR)sTemp);
				}
			} //while
			
		}  //if
		HttpSocket.CloseSocket();
	}  //while
	
	
	DownRegistry.Close();
	DownloadFile.Close();
	LeoDownInfo->bIsFileDown=FALSE;  //设置标志,此线程下载结束

	AfxEndThread(0,TRUE);
	return 0;

}
UINT TestSocketLink(void *lParam)
{
	//此函数中的一些说明在DownLoad()中可以找到
	CHttpDownLoad *the=(CHttpDownLoad*)lParam;

	CHttpSocket HttpSocket;
	CString strServer,strObject;
	DWORD dwServiceType;
	unsigned short nPort;
	long nLength;
	const char *pRequestHeader = NULL;
	char *pResponseHeader=NULL;
	char *pAcceptType=NULL;
	int nTimeout=the->m_stLeoDownInfo.stSocketType.nTimeOut;
	AfxParseURL((LPCTSTR)(the->m_stLeoDownInfo.strLocationUrl),dwServiceType,strServer,strObject,nPort);
	
	//------如果要下载文件,将文件名存入结构变量中用于自动更名算法------
	if(strObject.Mid(strObject.GetLength()-4,1)=="." || strObject.Mid(strObject.GetLength()-3,1)==".")
		the->m_stLeoDownInfo.strAutoFilePath=strObject;  

	the->m_stLeoDownInfo.stSocketType.strServer=strServer;  //保存服务器名 www.xxx.xx
	
	pRequestHeader = HttpSocket.FormatRequestHeader((LPTSTR)(LPCTSTR)strServer,(LPTSTR)(LPCTSTR)strObject,nLength,NULL,NULL,the->m_stLeoDownInfo.lFromeByte,the->m_stLeoDownInfo.lToByte,0,NULL);	
		
	HttpSocket.Socket();
	HttpSocket.Connect((LPTSTR)(LPCTSTR)strServer,nPort);
	HttpSocket.SendRequest();
	HttpSocket.SetTimeout(nTimeout,0);
	pResponseHeader=HttpSocket.GetResponseCharPoint();
	
	//::SendMessage(the->m_pMainFrame->m_hWnd,WM_TESTLIST,0,(LPARAM)pResponseHeader);
	int nLineSize = 0;
	char szLine[256];

	while(nLineSize != -1)
	{
		nLineSize = HttpSocket.GetResponseLine(szLine,256);
		if(nLineSize > -1)
		{
			szLine[nLineSize] = '\0';
			::SendMessage(the->m_pMainFrame->m_hWnd,WM_TESTLIST,0,(LPARAM)szLine);
		}
	}

	int nSvrState = HttpSocket.GetServerState();
	the->m_stLeoDownInfo.nSvrState=nSvrState;

	CString csState;
	csState.Format("%d",nSvrState);
	csState=csState.Left(1);
	if(csState=="3")
	{
		//重新定位下载网址
		char szValue[30];
		HttpSocket.GetField("Location",szValue,30);
		the->m_stLeoDownInfo.strLocationUrl.Format("%s",szValue);
		AfxParseURL((LPCTSTR)(the->m_stLeoDownInfo.strLocationUrl),dwServiceType,strServer,strObject,nPort);
		if(strServer.IsEmpty())
		{
			CString strLocation;
			strLocation="http://";
			strLocation+=the->m_stLeoDownInfo.stSocketType.strServer;
			strLocation+=the->m_stLeoDownInfo.strLocationUrl;
			the->m_stLeoDownInfo.strLocationUrl=strLocation;  //!!!新网址存入结构变量中

		}
	}
	else if(csState=="5")
	{
	}
	else if(csState=="2")
	{
		//成功连接服务器,线程结束
		char szLength[30];
		HttpSocket.GetField("Content-Length",szLength,30);
		long nFileSize = atol(szLength);
		the->m_stLeoDownInfo.lFileLength=nFileSize;	
	}
	
	HttpSocket.CloseSocket();
	AfxEndThread(0,TRUE);
	return 0;

}

UINT StartHttpDownLoad(void *lParam)
{
	//--------------------第一步--------------------
	//******定义一个注册表变量******
	CLRegistry DownRegistry;
	HKEY nhKeyRoot=HKEY_CURRENT_USER;
	//******定义一个CHttpDownLoad类的指针******
	CHttpDownLoad *the=(CHttpDownLoad*)lParam;

	//******向列表框写入数据******
	//如果"nBreakRev"为"0",说明是新的下载任务.
	if(the->m_stLeoDownInfo.nBreakRev!=1)
	{
		WRITEREGLISTCTRL_DATA pWriteRegListCtrlData;
		pWriteRegListCtrlData.nPID=the->m_stLeoDownInfo.nPID;
		pWriteRegListCtrlData.nItem=the->m_stLeoDownInfo.nPID-1; //列表框的行标(从0开始)
		pWriteRegListCtrlData.nImage=the->m_stLeoDownInfo.nImage; //图示
		pWriteRegListCtrlData.strFilePath=the->m_stLeoDownInfo.strFilePath; //文件下载后存盘的绝对路径
		pWriteRegListCtrlData.strLocationUrl=the->m_stLeoDownInfo.strLocationUrl; //文件下载的网址
		pWriteRegListCtrlData.strComment=the->m_stLeoDownInfo.strComment; //下载的提示信息
		pWriteRegListCtrlData.strRegPath=the->m_stLeoDownInfo.strRegSubPath; //保存的注册表路径
		//******向注册表写入下载数据******
		//注册表位置"HKEY_CURRENT_USER\Software\BLeo2004\DownLoad\Down?"
		//"Down?"中的"?"号为第几个下载任务如:Down1,Down2等.
		if(DownRegistry.Open(nhKeyRoot,pWriteRegListCtrlData.strRegPath))
		{
			DownRegistry.Write("Image",pWriteRegListCtrlData.nImage);
			DownRegistry.Write("FileName",pWriteRegListCtrlData.strFilePath);
			DownRegistry.Write("Comment",pWriteRegListCtrlData.strComment);		
			DownRegistry.Write("URL",pWriteRegListCtrlData.strLocationUrl);
			DownRegistry.Write("Percent","0%"); //***写入百分比这对以后的断点下载有用!
		}
		DownRegistry.Close();
		//******向CMainFrame发出WM_WRITEREGLISTCTRL消息,此消息用于向列表框写入数据.******
		::SendMessage(the->m_pMainFrame->m_hWnd,WM_WRITEREGLISTCTRL,0,(LPARAM)&pWriteRegListCtrlData);
	}	

	//******打开计时器,开始下载计时,the为CHttpDownLoad类的指针.******
	//1为第一个计时器,用于计算下载用的全部时间
	the->SetTimerBegin(1);

	//--------------------第二步--------------------------------------------
	//---此段程序向要下载文件的服务器发出查询,查看返回的结果是否正确,    ---
	//---如正确再下载,否则停止下载任务                                   ---
	//----------------------------------------------------------------------

	//******定义一个线程指针******
	CWinThread *pWinThread=NULL;      
	HANDLE hThreadTest=NULL;           //线程句柄
	DWORD dwSingleObject=0;            //WaitForSingleObject返回值
	int nSocketLinkNum=1;              //Socket连接次数,初始为1,终止为10
	while(nSocketLinkNum<=the->m_stLeoDownInfo.nSocketLinkNum)
	{	

		//******如果m_bIsEndThe为真,就将这个线程结束,那么这次的下载任务也将结果.******
		//这主要用于强制下载线程退出!
		if(the->m_bIsEndThe)
		{
			//停止计时
			the->KillTimerEnd(1);
			AfxEndThread(0,TRUE);  //结束线程
			return 0;   
		}
		

		//******WaitForSingleObject超时时间******
		DWORD lTimeOut=(DWORD)the->m_stLeoDownInfo.stSocketType.nTimeOut;

		pWinThread=AfxBeginThread(TestSocketLink,(void*)the); //开始创建测试线程
		hThreadTest=pWinThread->m_hThread; //赋值线程句柄
		dwSingleObject=WaitForSingleObject(hThreadTest,lTimeOut+500); //等侍线程结束
		int nSvrState=the->m_stLeoDownInfo.nSvrState; //返回服务器的状态值
		CString cs;
		long Length;
		cs.Format("%d",the->m_stLeoDownInfo.nSvrState);
		cs=cs.Left(1); //取状态值的第一位
		Length=the->m_stLeoDownInfo.lFileLength; //返回要下载文件的长度
		if(dwSingleObject==WAIT_TIMEOUT) //如果线程超时
		{
			//强制线程退出
			TerminateThread(hThreadTest,0);

			if(cs=="2" && Length>0)
				break;  
			if(nSvrState==500)
			{
				nSocketLinkNum+=12;
				break;
			}
		}
		else if(dwSingleObject==WAIT_OBJECT_0) //如果线程正常退出
		{
			//如果服务器返回是2XX并且下载文件的长度大于0,就表明测试成功,下一步就可以正式下载文件了
			if(cs=="2" && Length>0) 
				break;  //跳出While!!!
			if(nSvrState==500) //如果服务器返回是500,证明服务器出错,下载任务结束
			{
				nSocketLinkNum+=12;
				break;
			}
		}
		
		//******如果m_bIsEndThe为真,就将这个线程结束,那么这次的下载任务也将结果.******
		//这主要用于强制下载线程退出!
		if(the->m_bIsEndThe)
		{
			the->KillTimerEnd(1);
			//CloseHandle(hThreadTest);
			//ReleaseMutex(the->m_hEndMutex);
			AfxEndThread(0,TRUE);
			return 0;
		}
		the->m_stLeoDownInfo.stSocketType.nTimeOut+=1000;
		nSocketLinkNum++;
	}

	//nSocketLinkNum超过10次下载结束
	if(nSocketLinkNum>the->m_stLeoDownInfo.nSocketLinkNum)
	{
		the->KillTimerEnd(1);
		::SendMessage(the->m_pMainFrame->m_hWnd,WM_DECRSETHNUM,the->m_stLeoDownInfo.nPID-1,0);
		::MessageBox(NULL,"URL连接错误!","Leo",MB_OK|MB_ICONSTOP);
		AfxEndThread(0,TRUE);
		return 0;
	}

	//--------------------第三步--------------------------------------------
	//---      此段程序是在下载文件前做一些准被工作                      ---
	//----------------------------------------------------------------------

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -