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

📄 httpget.cpp

📁 此程式利用ftp與http協定提供多線程下載及斷點續傳功能
💻 CPP
字号:
// HttpGet.cpp: 实现CHttpGet类.
//
#include "stdafx.h"
#include "HttpGet.h"
#include "DealSocket.h"
#include "myfile.h"

int CHttpGet::m_nCount;
DWORD CHttpGet::m_nFileLength;

//---------------------------------------------------------------------------
CHttpGet::CHttpGet()
{
	m_nFileLength=0;
}

//---------------------------------------------------------------------------
CHttpGet::~CHttpGet()
{
}

//---------------------------------------------------------------------------
BOOL CHttpGet::HttpDownLoadProxy(
			CString strProxyAddr,
			int nProxyPort,
		    CString strHostAddr,
			CString strHttpAddr,
			CString strHttpFilename,
			CString strWriteFileName,
			int nSectNum)
{
	SOCKET hSocket;
	hSocket=ConnectHttpProxy(strProxyAddr,nProxyPort);

	if(hSocket == INVALID_SOCKET) return 1;
	// 发送文件头,计算文件大小.
	SendHttpHeader(hSocket,strHostAddr,strHttpAddr,strHttpFilename,0);
 	closesocket(hSocket);

    HttpDownLoad(
			strProxyAddr,
			nProxyPort,
		    strHostAddr,
			80,            // 无效.               
			strHttpAddr,
			strHttpFilename,
			strWriteFileName,
			nSectNum,
			true);

	return TRUE;
}

//---------------------------------------------------------------------------
BOOL CHttpGet::HttpDownLoadNonProxy(
		    CString strHostAddr,
			CString strHttpAddr,
			CString strHttpFilename,
			CString strWriteFileName,
			int nSectNum)
{
	int nHostPort=80;

	SOCKET hSocket;
	hSocket=ConnectHttpNonProxy(strHostAddr,nHostPort);
	if(hSocket == INVALID_SOCKET) return 1;
	// 发送文件头,计算文件大小.
	SendHttpHeader(hSocket,strHostAddr,strHttpAddr,strHttpFilename,0);
 	closesocket(hSocket);

    HttpDownLoad(
			TEXT(""),   // 无效.
			80,         // 无效. 
		    strHostAddr,
			nHostPort,
			strHttpAddr,
			strHttpFilename,
			strWriteFileName,
			nSectNum,
			false);

	return TRUE;
}

//---------------------------------------------------------------------------
BOOL CHttpGet::HttpDownLoad(
			CString strProxyAddr,
			int nProxyPort,
		    CString strHostAddr,
			int nHostPort,
			CString strHttpAddr,
			CString strHttpFilename,
			CString strWriteFileName,
			int nSectNum,
			BOOL bProxy)
{
	ASSERT(nSectNum>0);

	m_nCount=0;                                    // 把计数器清零.
	sectinfo=new CHttpSect[nSectNum];              // 给信息结构申请内存.
	DWORD nSize= m_nFileLength/nSectNum;           // 计算分割段的大小.

	int i;
	// 创建线程.
	for(i=0;i<nSectNum;i++)
	{
	    sectinfo[i].szProxyAddr=strProxyAddr;      // 代理服务器地址.
	    sectinfo[i].nProxyPort =nProxyPort;		   // Host地址.
	    sectinfo[i].szHostAddr =strHostAddr;       // Http文件地址.
	    sectinfo[i].nHostPort  =nHostPort;		   // Http文件名.
	    sectinfo[i].szHttpAddr =strHttpAddr;       // 代理服务端口号.
	    sectinfo[i].szHttpFilename=strHttpFilename;// Host端口号.
		sectinfo[i].bProxyMode=bProxy;		       // 下载模态. 


		// 计算临时文件名.
		CString strTempFileName;
		strTempFileName.Format("%s_%d",strWriteFileName, i);
        sectinfo[i].szDesFilename=strTempFileName; // 下载后的文件名.
	
		if(i<nSectNum-1){
			sectinfo[i].nStart=i*nSize;            // 分割的起始位置.
			sectinfo[i].nEnd=(i+1)*nSize;          // 分割的终止位置.
		}
		else{
			sectinfo[i].nStart=i*nSize;            // 分割的起始位置.
			sectinfo[i].nEnd=m_nFileLength;        // 分割的终止位置.
		}

		// AfxBeginThread(ThreadDownLoad,&sectinfo[i],THREAD_PRIORITY_HIGHEST);
		AfxBeginThread(ThreadDownLoad,&sectinfo[i]);
	}

	// 等待所有线程结束.
	while(m_nCount!=nSectNum);			

	FILE *fpwrite;

 	// 打开写文件.
	if((fpwrite=fopen(strWriteFileName,"wb"))==NULL){
  		return FALSE;
	}

	for(i=0;i<nSectNum;i++){
		FileCombine(&sectinfo[i],fpwrite);
	}

	fclose(fpwrite);

	delete[] sectinfo;
    
    return TRUE;
}

//---------------------------------------------------------------------------
BOOL CHttpGet::FileCombine(CHttpSect *pInfo, FILE *fpwrite)
{	
	FILE *fpread;
	
	// 打开文件.
	if((fpread=fopen(pInfo->szDesFilename,"rb"))==NULL)
		return FALSE;

	DWORD nPos=pInfo->nStart;
	
	// 设置文件写指针起始位置.
	fseek(fpwrite,nPos,SEEK_SET);
	
	int c;
	// 把文件数据写入到子文件.		
	while((c=fgetc(fpread))!=EOF)
	{
		fputc(c,fpwrite);
		nPos++;
		if(nPos==pInfo->nEnd) break;
	}
	
	fclose(fpread);
	DeleteFile(pInfo->szDesFilename);

	return TRUE;
}

//---------------------------------------------------------------------------
UINT CHttpGet::ThreadDownLoad(void* pParam)
{
	CHttpSect *pInfo=(CHttpSect*)pParam;
	SOCKET hSocket;

	if(pInfo->bProxyMode){	
		hSocket=ConnectHttpProxy(pInfo->szProxyAddr,pInfo->nProxyPort);
	}
	else{
		hSocket=ConnectHttpNonProxy(pInfo->szHostAddr,pInfo->nHostPort);
	}
	if(hSocket == INVALID_SOCKET) return 1;


	// 计算临时文件大小.
	DWORD nFileSize=myfile.GetFileSizeByName(pInfo->szDesFilename);
    DWORD nSectSize=(pInfo->nEnd)-(pInfo->nStart);

	// 此段已下载完毕.
	if(nFileSize==nSectSize){
		TRACE("文件已下载完毕!\n");
		CHttpGet::m_nCount++;  // 计数.
		return 0;
	}

    FILE *fpwrite=myfile.GetFilePointer(pInfo->szDesFilename);
	if(!fpwrite) return 1;

    // 设置下载范围.
	SendHttpHeader(hSocket,pInfo->szHostAddr,pInfo->szHttpAddr,
		      pInfo->szHttpFilename,pInfo->nStart+nFileSize);

	DWORD nLen; 
	DWORD nSumLen=0; 
	char szBuffer[1024];

	while(1)
	{
		if(nSumLen>=nSectSize-nFileSize) break;
		nLen=recv(hSocket,szBuffer,sizeof(szBuffer),0);
		if (nLen == SOCKET_ERROR){
			TRACE("Read error!\n");
			fclose(fpwrite);
			return 1;
		}

  		if(nLen==0) break;
		nSumLen +=nLen;
		TRACE("%d\n",nLen);

		// 把数据写入文件.		
		fwrite(szBuffer,nLen,1,fpwrite);
	}

    
	fclose(fpwrite);      // 关闭写文件.
	closesocket(hSocket); // 关闭套接字.
	CHttpGet::m_nCount++; // 计数.
	return 0;
}

//---------------------------------------------------------------------------
SOCKET CHttpGet::ConnectHttpProxy(CString strProxyAddr,int nPort)
{
	TRACE("正在建立连接\n");
	
  	CString sTemp;
	char cTmpBuffer[1024];
	SOCKET hSocket=dealsocket.GetConnect(strProxyAddr,nPort);

    if(hSocket == INVALID_SOCKET)
    {
		TRACE("连接http服务器失败!\n");
		return INVALID_SOCKET;
    }

	// 发送CONNCET请求令到代理服务器,用于和代理建立连接代理服务器的
	// 地址和端口放在strProxyAddr,nPort 里面.
	sTemp.Format("CONNECT %s:%d HTTP/1.1\r\nUser-Agent:\
		           MyApp/0.1\r\n\r\n",strProxyAddr,nPort);
	
	if(!SocketSend(hSocket,sTemp))
	{
		TRACE("连接代理失败\n");
		return INVALID_SOCKET;
	}

	// 取得代理响应,如果连接代理成功,代理服务器将
	// 返回"200 Connection established".
	int nLen=GetHttpHeader(hSocket,cTmpBuffer);
	sTemp=cTmpBuffer;
	if(sTemp.Find("HTTP/1.0 200 Connection established",0)==-1)
	{
		TRACE("连接代理失败\n");
		return INVALID_SOCKET;
	}

	TRACE(sTemp);
	TRACE("代理连接完成\n");
	return hSocket; 
}

//---------------------------------------------------------------------------
SOCKET CHttpGet::ConnectHttpNonProxy(CString strHostAddr,int nPort)
{
	TRACE("正在建立连接\n");
    SOCKET hSocket=dealsocket.GetConnect(strHostAddr,nPort);
	if(hSocket == INVALID_SOCKET)
		return INVALID_SOCKET;
    
	return hSocket;
}

//---------------------------------------------------------------------------
// 例如: strHostAddr="www.aitenshi.com",
// strHttpAddr="http://www.aitenshi.com/bbs/images/",
// strHttpFilename="pics.jpg".
BOOL CHttpGet::SendHttpHeader(SOCKET hSocket,CString strHostAddr,
				CString strHttpAddr,CString strHttpFilename,DWORD nPos)
{
	// 进行下载. 
	static CString sTemp;
	char cTmpBuffer[1024];

	// Line1: 请求的路径,版本.
	sTemp.Format("GET %s%s HTTP/1.1\r\n",strHttpAddr,strHttpFilename);
	if(!SocketSend(hSocket,sTemp)) return FALSE;

	// Line2:主机.
	sTemp.Format("Host: %s\r\n",strHostAddr);
	if(!SocketSend(hSocket,sTemp)) return FALSE;

	// Line3:接收的数据类型.
	sTemp.Format("Accept: \r\n");
	if(!SocketSend(hSocket,sTemp)) return FALSE;
	
	// Line4:参考地址.
    sTemp.Format("Referer: %s\r\n",strHttpAddr); 
	if(!SocketSend(hSocket,sTemp)) return FALSE;
		
	// Line5:浏览器类型.
	sTemp.Format("User-Agent: Mozilla/4.0 \
		(compatible; MSIE 5.0; Windows NT; DigExt; DTS Agent;)\r\n");

	if(!SocketSend(hSocket,sTemp)) return FALSE;

	// 续传. Range 是要下载的数据范围,对续传很重要.
	sTemp.Format("Range: bytes=%d-\r\n",nPos);
	if(!SocketSend(hSocket,sTemp)) return FALSE;
	
	// LastLine: 空行.
	sTemp.Format("\r\n");
	if(!SocketSend(hSocket,sTemp)) return FALSE;

	// 取得http头.
	int i=GetHttpHeader(hSocket,cTmpBuffer);
	if(!i)
	{
		TRACE("获取HTTP头出错!\n");
		return 0;
	}
	
	// 如果取得的http头含有404等字样,则表示连接出问题.
	sTemp=cTmpBuffer;
	if(sTemp.Find("404")!=-1) return FALSE;

	// 得到待下载文件的大小.
	m_nFileLength=GetFileLength(cTmpBuffer);

	// 因为TRACE()函数最大的字符串长度为255.
    TRACE(CString(cTmpBuffer).GetBuffer(200));

	return TRUE;
}

//---------------------------------------------------------------------------
DWORD CHttpGet::GetHttpHeader(SOCKET sckDest,char *str)
{
	BOOL bResponsed=FALSE;
	DWORD nResponseHeaderSize;
	
	if(!bResponsed)
	{
		char c = 0;
		int nIndex = 0;
		BOOL bEndResponse = FALSE;
		while(!bEndResponse && nIndex < 1024)
		{
			recv(sckDest,&c,1,0);
			str[nIndex++] = c;
			if(nIndex >= 4)
			{
				if( str[nIndex - 4] == '\r' && 
					str[nIndex - 3] == '\n' && 
					str[nIndex - 2] == '\r' && 
					str[nIndex - 1] == '\n')
					bEndResponse = TRUE;
			}
		}

		str[nIndex]=0;
		nResponseHeaderSize = nIndex;
		bResponsed = TRUE;
	}
	
	return nResponseHeaderSize;
}

//---------------------------------------------------------------------------
DWORD CHttpGet:: GetFileLength(char *httpHeader)
{
	CString strHeader;
	CString strFind=_T("Content-Length:");
	int local;
	strHeader=CString(httpHeader);
	local=strHeader.Find(strFind,0);
	local+=strFind.GetLength();
	strHeader.Delete(0,local);
	local=strHeader.Find("\r\n");
	
	if(local!=-1){
      strHeader=strHeader.Left(local);
	}

	return atoi(strHeader);
}

//---------------------------------------------------------------------------
BOOL CHttpGet::SocketSend(SOCKET sckDest,CString szHttp)
{
	int iLen=szHttp.GetLength();
	if(send (sckDest,szHttp,iLen,0)==SOCKET_ERROR)
	{
		closesocket(sckDest);
		TRACE("发送请求失败!\n");
		return FALSE;
	}
	
	return TRUE;
}

⌨️ 快捷键说明

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