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

📄 httpsdownload.cpp

📁 多线程下载工具可支持http,ftp,https多协议....vc编写
💻 CPP
字号:
// HTTPSDownload.cpp: implementation of the CHTTPSDownload class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "download.h"
#include "HTTPSDownload.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
 DWORD WINAPI HSDownloadThread(LPVOID);
 DWORD WINAPI HSNotify(LPVOID); 

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////


 //包含HTTPS下载函数,利用OpenSSL库进行加密的数据传输,其具体下载实现与http基本相同
 CHTTPSDownload::CHTTPSDownload()
{
   for(int  i=0; i<10; i++)
   {
	  m_hThread[i] = NULL;
	  m_bTerminate[i] = FALSE;
	  ss[i]=0;
	  m_sum[i]=0;
   }
   m_SupportResume = FALSE;
   m_bResume = FALSE;
}

CHTTPSDownload::~CHTTPSDownload()
{

}

void  CHTTPSDownload::Begin(CString Allurl, CString Saveas, int nParts)
{
    for(int i=0;i<10;i++){
			m_state.wcsize[i] = 0;
			m_sum[i] = 0;
			ss[i]=0;
			m_dwFileSize=0;
	}
	
	
	if(!(AnalyseURL(Allurl)))
	{
	  AfxMessageBox("URL错误,请确认地址正确");
	  return;
    }
  
    m_strSavePath = Saveas;
    m_nParts = nParts;
    m_strSavePath.TrimLeft();
    m_strSavePath.TrimRight();

    if(SendRequest() != HS_LINK_OK) { AfxMessageBox("下载出现错误"); return; }
 	
    m_strTempSavePath = m_strSavePath;
	m_strTempSavePath += ".down";
	
	FILE* fp = NULL;
	if((fp = fopen(m_strTempSavePath, "r")) == NULL){
		m_state.range[0] = -1;
		m_bResume = FALSE;
	}
	else{
		m_bResume = TRUE;
		fread(m_state.range, sizeof(LONG), 2*nParts, fp);
		fread(m_state.threadsize, sizeof(LONG), nParts, fp);
		fread(m_state.wcsize, sizeof(LONG), nParts, fp);
		fclose(fp);
		DeleteFile(m_strTempSavePath); 
	}

    if(m_state.range[0] == -1){
	

    for(int i = 0; i < m_nParts; i++){
			m_state.range[i * 2] = i * (m_dwFileSize /m_nParts);
			m_state.range[i * 2 + 1] = (i + 1) * (m_dwFileSize / m_nParts) - 1;
			m_state.threadsize[i] = m_state.range[i * 2 + 1] - m_state.range[i * 2];
		}
		m_state.range[2*m_nParts-1] = m_dwFileSize;
		m_state.threadsize[m_nParts-1] = m_state.range[2*m_nParts-1] - m_state.range[2*m_nParts-2];
	}
	CreateThread();  
	
	return ;
}

BOOL CHTTPSDownload::AnalyseURL(CString Allurl)
{

	m_strServer = _T("");
	m_strObject = _T("");
	m_Port	  = 0;

	Allurl.TrimLeft();
	Allurl.TrimRight();
	CString strTemp;
	int n=Allurl.Find("://");
	if(n == -1)  return FALSE; 
	strTemp = Allurl.Mid(n+3);
	
    n=strTemp.Find('/');
	if(n == -1)  return FALSE;
	m_strServer = strTemp.Left(n);
	m_strObject = strTemp.Mid(n);
    
	n = m_strServer.Find(':');
	if(n != -1)
	{
        CString temp = m_strServer.Mid(n+1);
        m_Port = (USHORT)_ttoi((LPCTSTR)temp);
		m_strServer = m_strServer.Left(n);
	}
	else
	{
		m_Port = 443;
	}
    return TRUE;
}


UINT CHTTPSDownload::SendRequest()
{
	CString	 strSend,strHeader;
	CString  m_P;
	m_P.Empty();  m_P.Format("%d",m_Port);
	strHost = m_strServer+":"+m_P;
	int      ret;
    SSL_CTX *ssl_ctx=NULL;
    SSL *ssl;
    BIO *bio;
	char	 ReadBuf[1025];
	DWORD	 Length,Code;

    while(TRUE)
	{
		//应用OpenSSL的加密连接进行与服务器的连接
	    if (ssl_ctx != NULL) SSL_CTX_free(ssl_ctx);
        SSL_load_error_strings();
        OpenSSL_add_ssl_algorithms();
        ssl_ctx=SSL_CTX_new(SSLv23_client_method());
        
		bio = BIO_new_ssl_connect(ssl_ctx);
        BIO_get_ssl(bio, & ssl);
        
		BIO_set_conn_hostname(bio, strHost.GetBuffer(0));


		
		strSend  = "GET " + m_strObject + " HTTP/1.1\r\n";
		strSend += "Host: " + m_strServer + "\r\n";
		strSend += "Accept: */*\r\n";
		strSend += "Pragma: no-cache\r\n"; 
		strSend += "Cache-Control: no-cache\r\n";
		strSend += "Connection: close\r\n";
		strSend += "Range: bytes=100-\r\n";
		strSend += "\r\n";

		ret = BIO_write(bio,strSend.GetBuffer(0), strSend.GetLength());
		strSend.ReleaseBuffer();
		
		strHeader.Empty();
        ZeroMemory(ReadBuf,1025);
		ret = BIO_read(bio, ReadBuf, 1025);
		strHeader += ReadBuf;
		strHeader += "\r\n";

		BOOL sign=AnalyseReceive(strHeader,Length, Code);
		
		if(sign)
		{
			if(linkcode==1)
			{
				if (Code == 206 )	
				{
					m_SupportResume = TRUE;
					m_dwFileSize = Length + 100;
				}
				  else						
				{
					m_SupportResume = FALSE;
					m_dwFileSize = Length + 100;
				}

				return HS_LINK_OK;
			}

			if(linkcode==2)  continue;
		}
		else
		{
			if(linkcode==-1) { AfxMessageBox("服务器返回信息错误"); return HS_LINK_ERROR;}
			if(linkcode==-2) { AfxMessageBox("服务器连接错误"); return HS_LINK_ERROR;}
		}
	}
	BIO_free_all(bio);
	if (ssl_ctx != NULL) SSL_CTX_free(ssl_ctx);

}


BOOL CHTTPSDownload::AnalyseReceive(CString ReadBuf, DWORD &Length, DWORD &Code)
{
	Length = 0;
	Code	= 0;

    CString strHeader =ReadBuf;
	strHeader.MakeLower();
	
    int n = strHeader.Find("\r\n");
	if (n == -1)   { linkcode =-1; return false; }
	CString strFirstLine = strHeader.Left(n);


	strFirstLine.TrimLeft();
	strFirstLine.TrimRight();
	n = strFirstLine.Find(' ');
    if (n == -1)   { linkcode =-1; return false; }
	strFirstLine = strFirstLine.Mid(n+1);
	n = strFirstLine.Find(' ');
	if (n == -1)   { linkcode =-1; return false; }
	strFirstLine = strFirstLine.Left(n);
	Code = (DWORD)_ttoi((LPCTSTR)strFirstLine);
	

	if( Code >= 300 && Code < 400 ) 
	{
		n = strHeader.Find("location:");
		if (n == -1)   { linkcode =-1; return false; }

		CString strRedirectURL = strHeader.Mid(n + strlen("location:"));
		n = strRedirectURL.Find("\r\n");
		if (n == -1)   { linkcode =-1; return false; }

		strRedirectURL = strRedirectURL.Left(n);
		strRedirectURL.TrimLeft();
		strRedirectURL.TrimRight();
	    
		n = strRedirectURL.ReverseFind('/');
		CString temp = strRedirectURL.Mid(n+1);
	
	    n = temp.Find('?');
	    if(n != -1)
		{
          temp=temp.Left(n);
		}

		n = m_strSavePath.ReverseFind('\\');
        m_strSavePath = m_strSavePath.Left(n+1);
		m_strSavePath+= temp;

        if(!(AnalyseURL(strRedirectURL)))
		{
	      linkcode =-1; return false;
		}
		linkcode=2;	return true;
	}

    if( Code >=400  )  { linkcode =-2; return false; }


	n = strHeader.Find("content-length:");
	if (n == -1)   {linkcode =-1;  return false; }

	CString strDownFileLen = strHeader.Mid(n + strlen("content-length:"));	
	n = strDownFileLen.Find("\r\n");
	if (n == -1)   {linkcode =-1;  return false; }

	strDownFileLen = strDownFileLen.Left(n);	
	strDownFileLen.TrimLeft();
	strDownFileLen.TrimRight();
	
	Length = (DWORD) _ttoi( (LPCTSTR)strDownFileLen );

    linkcode=1; return true;
}


void CHTTPSDownload::CreateThread()
{
	if(m_SupportResume){
		DWORD dwThread;
		m_index = 0;
		for(int i = 0; i < m_nParts; i++)
		{
			m_bTerminate[i] = FALSE;
			m_hThread[i] = ::CreateThread(NULL, 0, HSDownloadThread, (LPVOID)this, 0, &dwThread);

		}
	}
	else{
		
		DWORD dwThread;
		m_index = 0;
		m_bTerminate[0] = FALSE;
		m_hThread[0] = ::CreateThread(NULL, 0, HSDownloadThread, (LPVOID)this, 0, &dwThread);

	}
	DWORD dwNotify;
	m_hNotify = ::CreateThread(NULL, 0, HSNotify, (LPVOID)this, 0, &dwNotify);

}


DWORD WINAPI HSDownloadThread(LPVOID lpParam)
{
	CHTTPSDownload* pThis = (CHTTPSDownload*)lpParam;
	int index;
	index = pThis->m_index;
	InterlockedIncrement(&pThis->m_index);
    pThis->ThreadFunc(index);
	return 0L;
}

DWORD WINAPI HSNotify(LPVOID lpParam)
{
    CHTTPSDownload* pThis = (CHTTPSDownload*)lpParam;
    pThis->Finish();
	return 0L;
}


void CHTTPSDownload::ThreadFunc(int index)
{
	
	if(m_state.range[2*index] ==-99) { ss[index]=1000; m_sum[index]=m_state.threadsize[index]; return; }
	
	m_sum[index] =0;

    SSL_CTX *ssl_ctx=NULL;
    SSL *ssl;
    BIO *bio;

    SSL_load_error_strings();
    OpenSSL_add_ssl_algorithms();
    ssl_ctx=SSL_CTX_new(SSLv23_client_method());
    bio = BIO_new_ssl_connect(ssl_ctx);

    BIO_get_ssl(bio, & ssl);

    BIO_set_conn_hostname(bio, strHost.GetBuffer(0));
    
    CString strSend, strRange;
	char szReadBuf[1025];

	strSend  = "GET " + m_strObject + " HTTP/1.1\r\n";
	strSend += "Host: " + m_strServer + "\r\n";
	strSend += "Accept: */*\r\n";
	strSend += "Pragma: no-cache\r\n"; 
	strSend += "Cache-Control: no-cache\r\n";
    strSend += "Connection: close\r\n";
	strRange.Format("Range: bytes=%d-%d\r\n", m_state.range[2 * index], m_state.range[2 * index + 1]);
    if(m_SupportResume)
		strSend += strRange;
	strSend += "\r\n";

	int ret = BIO_write(bio,strSend.GetBuffer(0), strSend.GetLength());
	strSend.ReleaseBuffer();

	ZeroMemory(szReadBuf,1025);
	ret = BIO_read(bio, szReadBuf, 1025);
		
	int n = GetHeadLength(szReadBuf);		
	
	CFile file;
	CString name;
	name.Format("%d", index);
	name = m_strTempSavePath + name;
	
	if(!m_bResume)
	  file.Open(name, CFile::modeCreate | CFile::modeWrite);
	else
	  file.Open(name, CFile::modeWrite);


	file.SeekToEnd();

	file.Write(szReadBuf + n, ret - n);
	int sum = ret - n, num = 0;

	if(!m_SupportResume) m_state.threadsize[0]=m_dwFileSize;

	while(1){
		if(m_bTerminate[index]){
			m_state.range[2 * index] = m_state.range[2 * index] + sum;
            m_state.wcsize[index] = m_sum[index];
            return;
		}
		ZeroMemory(szReadBuf,1025);
		
		num = BIO_read(bio,szReadBuf, 1025);
		if(num<=0) break;
			
		file.Write(szReadBuf, num);
		sum += num; 
		m_sum[index]=sum+m_state.wcsize[index];
			
		ss[index]=long((1.0*m_sum[index])*1000/m_state.threadsize[index]);
	}
	
	file.Close();
	BIO_free_all(bio);
	SSL_CTX_free(ssl_ctx);

    m_state.range[2*index]= -99;
	return ;
}


int CHTTPSDownload::GetHeadLength(char *lpData)
{
	int nhead = 0,nstr; 
	while(1){
		nstr=0;
		BOOL bLine = FALSE;
	    while ( bLine == FALSE && nhead < 1025 )
		{
		  char ch = (char)(lpData[nhead]);
		  if(ch=='\n')  bLine = TRUE;
		  if(ch!='\n'&&ch!='\r') nstr++;
		  nhead++;
		 }
		
		if(nstr==0)  break;
	}
	return (nhead);
}



void CHTTPSDownload::Finish()
{
	char* lpData = NULL;
	if(m_SupportResume){
		HRESULT ret = WaitForMultipleObjects(m_nParts, m_hThread, TRUE, INFINITE);
		if(m_bTerminate[0]){
			return;
		}
		if(ret == 0){
		
			
			CFile file, f[10];
			CString name;
			
			file.Open(m_strSavePath, CFile::modeCreate | CFile::modeWrite);
			for(int i = 0; i <m_nParts; i++){
				name.Empty();
				name.Format(".down%d", i);
				name = m_strSavePath + name;
			    f[i].Open(name, CFile::modeRead);
				DWORD len = f[i].GetLength();
				if(lpData){
					delete [] lpData;
					lpData = NULL;
				}
				if(lpData == NULL){
					lpData = new char[len];
				}
				f[i].Read(lpData, len);
				file.Write(lpData, len);
				f[i].Close();
				DeleteFile(name);
			}
			if(lpData){
				delete [] lpData;
				lpData = NULL;
			}
			file.Close();
			name.Empty();
			name = m_strSavePath + ".down";
			DeleteFile(name);
			AfxMessageBox("下载完成");
		}
	}
	else{
		HRESULT ret = WaitForSingleObject(m_hThread[0], INFINITE);
		if(m_bTerminate[0]){
			return ;
		}
		if(ret == 0){
		
		
			CFile file, f;
			CString name;
			
			file.Open(m_strSavePath, CFile::modeCreate | CFile::modeWrite);
			name = m_strSavePath + ".down0";
			f.Open(name, CFile::modeRead);
			DWORD len = f.GetLength();
			if(lpData){
				delete [] lpData;
				lpData = NULL;
			}
			if(lpData == NULL){
				lpData = new char[len];
			}
			f.Read(lpData, len);
			file.Write(lpData, len);
			f.Close();
			DeleteFile(name);
		
			if(lpData){
				delete [] lpData;
				lpData = NULL;
			}
			file.Close();
			AfxMessageBox("下载完成");
		}
	}
	if(lpData){
		delete [] lpData;
		lpData = NULL;
	}
	return ;
}

void CHTTPSDownload::OnCancel() 
{
	

	for(int i = 0; i < m_nParts; i++)
		m_bTerminate[i] = TRUE;
    HRESULT ret = WaitForSingleObject(m_hNotify, INFINITE);
	if(ret != WAIT_OBJECT_0) return;

	FILE* fp = NULL;
	CString name;
	name = m_strSavePath + ".down";
    fp = fopen(name, "w+") ;

	fwrite(m_state.range, sizeof(LONG), 2*m_nParts, fp);
	fwrite(m_state.threadsize, sizeof(LONG), m_nParts, fp);
	fwrite(m_state.wcsize, sizeof(LONG), m_nParts, fp);
	fclose(fp);
}





   

⌨️ 快捷键说明

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