断点续传控制台版本

HTTP多线程下载实现
#include <afxinet.h>

#define CHTTPDOWNLOAD_MINTHREADIDS 1
#define CHTTPDOWNLOAD_MAXTHREADIDS 5
#define CHTTPDOWNLOAD_SUBURLSAVEASEXTENSION ".~tmp"
#define CHTTPDOWNLOAD_BUFFERSIZE 4096
#define CHTTPDOWNLOAD_EXCEPTION "ExceptionHTTPReceiveMonitor"

class CHttpDownloader
{
private:
 struct BEGINEND
 {
  DWORD m_dwBegin;
  DWORD m_dwEnd;
  CString m_strSubRequestURLSaveAs;
  CString m_strRequestURL;
  CString m_strSession;
  CString m_strRange;
  CHttpDownloader * m_pOwner;
  DWORD m_dwThreadOrder;
  CString m_strServer;
  INTERNET_PORT m_nPort;
  CString m_strObject;
  BOOL m_bCompleted;
 };
 CString m_strRequestURL; // 请求的URL
 CString m_strRequestURLSaveAs; // URL另存为
  CString m_strDefURLSaveAsPath; // URL另存为默认路径
 DWORD m_dwServiceType; // URL协议类型
 CString m_strServer; // URL服务器
 CString m_strObject; // URL对象
 INTERNET_PORT m_nPort; // RUL端口
 DWORD m_dwSourceFileSize; // URL文件大小
 DWORD m_dwBEGINENDs; // 区间数
  CRITICAL_SECTION m_cs; // 临界区
 BEGINEND * m_pBEGINEND; // 区间口地址
 DWORD * m_pdwHTTPReceiveThreadID; // 线程ID
 HANDLE * m_phHTTPReceiveThread; // 线程句柄
 DWORD m_dwHTTPReceiveMonitorThreadID; // 线程ID
 HANDLE m_hHTTPReceiveMonitorThread; // 线程句柄
private:
 ULONGLONG ullGetSourceFileSize(LPCTSTR pstrServer,LPCTSTR pstrObject,INTERNET_PORT nPort)
 {
  ULONGLONG ullFilelength=0;

  SYSTEMTIME st;
  GetLocalTime(&st);
  CString strLocalTime;
  strLocalTime.Format("%u%u%u%u%u%u%u%u",st.wYear,st.wMonth,st.wDayOfWeek,st.wDay,st.wHour,st.wMinute,st.wSecond,st.wMilliseconds);
  CInternetSession session(strLocalTime);

  CHttpConnection* pServer = NULL;
  CHttpFile* pFile = NULL;
  DWORD dwRet=~HTTP_STATUS_OK;

  CString strServerName=pstrServer;

  pServer = session.GetHttpConnection(strServerName, nPort);
  pFile = pServer->OpenRequest(CHttpConnection::HTTP_VERB_GET,pstrObject);

  pFile->SendRequest();
  pFile->QueryInfoStatusCode(dwRet);
  if(dwRet == HTTP_STATUS_OK)
  {
   CString strRange;
   if(pFile->QueryInfo(HTTP_QUERY_CONTENT_LENGTH,strRange,NULL))ullFilelength=atoull((LPSTR)(LPCSTR)strRange);
  }

  delete pFile;
  delete pServer;

  session.Close();
  return ullFilelength;
 }

 ULONGLONG power(BYTE exp)
 {
  if(exp==0)return 1;
  ULONGLONG ullRet=10;
  for(BYTE i=1;i<exp;i++)ullRet*=10;
  return ullRet;
 }

 ULONGLONG atoull(LPSTR pszInfo)
 {
  if(!pszInfo)return 0;

  ULONGLONG ullRet=0;
  CHAR szBuf[21]={0};
  LPSTR pszBuf=szBuf;
  while(*pszInfo!=0)*pszBuf++=*pszInfo++;
  BYTE i=0;
  pszBuf--;
  while(pszBuf+1!=szBuf)ullRet+=(*pszBuf---48)*power(i++);

  return ullRet;
 }

 DWORD dwtoa2(DWORD e,CHAR * c,DWORD l)
 {
  /* usage
  CHAR c[12]={0}; //0~(1~10)~11
  g_mdicreate.szTitle=&c[dwtoa2(++g_lWndNum,c,sizeof(c))];
  */
  DWORD a=(DWORD)e;
  DWORD aa=a;
  if(aa<0)a*=-1;
  DWORD b=-1;
  DWORD cc=l-2;
  while(1)
  {
   b=a%10;
   a=a/10;
   c[cc]=(CHAR)b+48;
   cc--;
   if (a==0)break;
  }
  aa>=0?cc++:c[cc]='-';
  return cc;
 }

 BOOL bCalculateSegmentSize()
 {
  if(m_dwSourceFileSize<=0)return FALSE;
  if(m_pBEGINEND)
  {
   delete[] m_pBEGINEND;
   m_pBEGINEND=NULL;
  }
  m_dwBEGINENDs=m_dwSourceFileSize<=m_dwBEGINENDs?CHTTPDOWNLOAD_MINTHREADIDS:CHTTPDOWNLOAD_MAXTHREADIDS;
  m_pBEGINEND=new BEGINEND[m_dwBEGINENDs];
  m_dwSourceFileSize--;
  DWORD m_dwAverageSegmentSize=m_dwSourceFileSize/m_dwBEGINENDs;
  DWORD m_dwRemainderSegmentSize=m_dwSourceFileSize%m_dwBEGINENDs;
  for (DWORD i=0,j=0,k=0;i<m_dwSourceFileSize && k<m_dwBEGINENDs;j=i+m_dwAverageSegmentSize,i=j,k++)
  {
   m_pBEGINEND[k].m_dwBegin=j;
   m_pBEGINEND[k].m_dwEnd=m_pBEGINEND[k].m_dwBegin+m_dwAverageSegmentSize+(k==m_dwBEGINENDs-1?0:-1);
   if(k==m_dwBEGINENDs-1)
   {
    if(m_dwRemainderSegmentSize)
    {
     m_pBEGINEND[k].m_dwEnd+=m_dwRemainderSegmentSize;
    }
   }

   CHAR c[12]={0};
   CHAR * pszNameOfFileWithFullPath=(CHAR *)(const CHAR *)m_strRequestURLSaveAs;
   CHAR * pszFilePath=0;
   GetFileInfo(pszNameOfFileWithFullPath,pszFilePath);
   if(pszFilePath)
   {
    m_pBEGINEND[k].m_strSubRequestURLSaveAs.Format("%s//%s%s%s",pszFilePath,pszNameOfFileWithFullPath,&c[dwtoa2(k,c,sizeof(c))],CHTTPDOWNLOAD_SUBURLSAVEASEXTENSION);
    delete[]pszFilePath;
    pszFilePath=0;
   }
   else
   {
    m_pBEGINEND[k].m_strSubRequestURLSaveAs.Format("%s//%s%s%s",m_strDefURLSaveAsPath,pszNameOfFileWithFullPath,&c[dwtoa2(k,c,sizeof(c))],CHTTPDOWNLOAD_SUBURLSAVEASEXTENSION);
   }
   HANDLE hSubRequestURLSaveAs=CreateFile(m_pBEGINEND[k].m_strSubRequestURLSaveAs,FILE_ALL_ACCESS,FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_ARCHIVE,NULL);
   if(INVALID_HANDLE_value!=hSubRequestURLSaveAs)
   {
    DWORD dwSubRequestURLSaveAsFileSize=GetFileSize(hSubRequestURLSaveAs,NULL);
    if(INVALID_FILE_SIZE!=dwSubRequestURLSaveAsFileSize)
    {
     m_pBEGINEND[k].m_dwBegin+=dwSubRequestURLSaveAsFileSize;
    }
    CloseHandle(hSubRequestURLSaveAs);
   }

   m_pBEGINEND[k].m_strRequestURL=m_strRequestURL;
   
   SYSTEMTIME st;
   GetLocalTime(&st);
   CString strLocalTime;
   strLocalTime.Format("%u%u%u%u%u%u%u%u",st.wYear,st.wMonth,st.wDayOfWeek,st.wDay,st.wHour,st.wMinute,st.wSecond,st.wMilliseconds);
   m_pBEGINEND[k].m_strSession.Format("%s",strLocalTime);

   m_pBEGINEND[k].m_strRange.Format("Range:bytes=%lu-%lu/r/n",m_pBEGINEND[k].m_dwBegin,m_pBEGINEND[k].m_dwEnd);
   m_pBEGINEND[k].m_pOwner=this;
   m_pBEGINEND[k].m_dwThreadOrder=k;
   m_pBEGINEND[k].m_strServer=m_strServer;
   m_pBEGINEND[k].m_nPort=m_nPort;
   m_pBEGINEND[k].m_strObject=m_strObject;
   m_pBEGINEND[k].m_bCompleted=FALSE;

   printf("[%lu-%lu] %s/n",m_pBEGINEND[k].m_dwBegin,m_pBEGINEND[k].m_dwEnd,m_pBEGINEND[k].m_strSubRequestURLSaveAs);
  }
  return TRUE;
 }

 void GetFileInfo(CHAR * & pszNameOfFileWithFullPath,CHAR * & pszFilePath)
 {
  /* usage
  CHAR * pszNameOfFileWithFullPath="E://Program Files//Thunder Network//Thunder//ThunderShell.exe";
  CHAR * pszFilePath=0;
  GetFileInfo(pszNameOfFileWithFullPath,pszFilePath);
  if(pszFilePath)
  {
   printf("%s/n",pszNameOfFileWithFullPath);
   printf("%s/n",pszFilePath);
   delete[]pszFilePath;
   pszFilePath=0;
  }
  */
  CHAR * pszWorkBuffer=0;
  CHAR * pszNameOfFileWithFullPath2=0;
  LONG lBufLength=1;
  try
  {
   pszNameOfFileWithFullPath2=pszNameOfFileWithFullPath;
   while(*pszNameOfFileWithFullPath2++!=0)++lBufLength;
   if(lBufLength<=1)throw "exception@GetFileInfo";
   pszWorkBuffer=new CHAR[lBufLength];
   memset(pszWorkBuffer,0,lBufLength);
   pszNameOfFileWithFullPath2=pszWorkBuffer;
   while(*pszNameOfFileWithFullPath!=0)*pszNameOfFileWithFullPath2++=*pszNameOfFileWithFullPath++;
   while (*--pszNameOfFileWithFullPath2!='//' && pszNameOfFileWithFullPath2>=pszWorkBuffer);
   if(pszNameOfFileWithFullPath2<pszWorkBuffer)throw "exception@GetFileInfo";
   *pszNameOfFileWithFullPath2=0;
   pszNameOfFileWithFullPath=++pszNameOfFileWithFullPath2;
   pszFilePath=pszWorkBuffer;
  }
  catch(...)
  {
   pszNameOfFileWithFullPath=0;
   pszFilePath=0;
   delete[]pszWorkBuffer;
   pszWorkBuffer=0;
  }
 }

 void ObtainDefURLSaveAsPath()
 {
  CHAR * pszCurrentDirectory=NULL;
  DWORD dwLength=GetCurrentDirectory(0,NULL);
  pszCurrentDirectory=new CHAR[dwLength];
  GetCurrentDirectory(dwLength,pszCurrentDirectory);
   m_strDefURLSaveAsPath.Format("%s",pszCurrentDirectory);
  delete[] pszCurrentDirectory;
 }

 static DWORD WINAPI HTTPReceive(LPVOID lpParameter)
 {
  BEGINEND * pOwner=(BEGINEND *)lpParameter;
  if(!pOwner)return -1;

  DWORD k=pOwner->m_dwThreadOrder;

  CInternetSession session(pOwner->m_strSession);
  CHttpConnection* pServer = NULL;
  CHttpFile* pFile = NULL;
  DWORD dwRet=~HTTP_STATUS_OK;

  CString strServerName=pOwner->m_strServer;

  pServer = session.GetHttpConnection(strServerName, pOwner->m_nPort);
  pFile = pServer->OpenRequest(CHttpConnection::HTTP_VERB_GET,pOwner->m_strObject);

  pFile->AddRequestHeaders(pOwner->m_strRange);
  printf("thread %d : %s/n",k,pOwner->m_strRange);

  pFile->SendRequest();
  pFile->QueryInfoStatusCode(dwRet);

  if(dwRet == HTTP_STATUS_PARTIAL_CONTENT)
  {
   BYTE * pBuf=new BYTE[CHTTPDOWNLOAD_BUFFERSIZE];
    FILE * pf=fopen(pOwner->m_strSubRequestURLSaveAs,"w+b");
    if(pf)
    {
     UINT nRead = pFile->Read(pBuf, CHTTPDOWNLOAD_BUFFERSIZE);
     while (nRead > 0)
     {
      fwrite(pBuf,1,nRead,pf);
      nRead = pFile->Read(pBuf, CHTTPDOWNLOAD_BUFFERSIZE);
     }
     fclose(pf);
    }
   if(pBuf)delete[]pBuf;
  }

  delete pFile;
  delete pServer;

  session.Close();

  pOwner->m_bCompleted=TRUE;

  return 0;
 }
 
 static DWORD WINAPI HTTPReceiveMonitor(LPVOID lpParameter)
 {
  CHttpDownloader * pOwner=(CHttpDownloader*)lpParameter;
  if(!pOwner)return -1;
  
  if(!pOwner->m_dwBEGINENDs)return -1;
  //
  for(DWORD i=0;i<pOwner->m_dwBEGINENDs;i++)ResumeThread(pOwner->m_phHTTPReceiveThread[i]);
  //
  DWORD dwRet;
  while(1)
  {
   dwRet=WaitForMultipleObjects(pOwner->m_dwBEGINENDs,pOwner->m_phHTTPReceiveThread,TRUE,20);
   if(WAIT_OBJECT_0==dwRet)
   {
    BYTE * pBuf=new BYTE[CHTTPDOWNLOAD_BUFFERSIZE];
    if(pBuf)
    {
     FILE * pf2=fopen(pOwner->m_strRequestURLSaveAs,"w+b");
     if(pf2)
     {
      for(i=0;i<pOwner->m_dwBEGINENDs;i++)
      {
       if(pOwner->m_phHTTPReceiveThread[i])
       {
        CloseHandle(pOwner->m_phHTTPReceiveThread[i]);
        pOwner->m_phHTTPReceiveThread[i]=NULL;
       }

       FILE * pf=fopen(pOwner->m_pBEGINEND[i].m_strSubRequestURLSaveAs,"r+b");
       if(pf)
       {
        size_t r=fread(pBuf,1,CHTTPDOWNLOAD_BUFFERSIZE,pf);
        while(r)
        {
         fwrite(pBuf,1,r,pf2);
         r=fread(pBuf,1,CHTTPDOWNLOAD_BUFFERSIZE,pf);
        }

        fclose(pf);
        //DeleteFile(pOwner->m_pBEGINEND[i].m_strSubRequestURLSaveAs);
       }

      }

      fclose(pf2);
     }

     delete[] pBuf;
    }

    break;
   }
   else if(WAIT_TIMEOUT==dwRet)
   {
    DWORD dwBEGINENDs=pOwner->GetdwBEGINENDs();
    if(0==dwBEGINENDs)
    {
     printf("%s/n","exception@creating thread");
     throw CString(CHTTPDOWNLOAD_EXCEPTION);
     return -1;
    }
   }
  }
  
  printf("%s all done!/npress any key to continue .../n",pOwner->m_strRequestURLSaveAs);
  return 0;
 }

 DWORD GetdwBEGINENDs()
 {
  EnterCriticalSection(&m_cs);
   DWORD dwBEGINENDs=m_dwBEGINENDs;
  LeaveCriticalSection(&m_cs);

  return dwBEGINENDs;
 }

 VOID SetdwBEGINENDs(DWORD dwBEGINENDs)
 {
  EnterCriticalSection(&m_cs);
   m_dwBEGINENDs=dwBEGINENDs;
  LeaveCriticalSection(&m_cs);
 }

 VOID ExceptionHTTPReceiveMonitor(DWORD dwExitCode)
 {
  if(m_phHTTPReceiveThread)
  {
   for(DWORD i=0;i<m_dwBEGINENDs;i++)
   {
    TerminateThread(m_phHTTPReceiveThread[i],dwExitCode);
    CloseHandle(m_phHTTPReceiveThread[i]);
   }

   delete[] m_phHTTPReceiveThread;
   m_phHTTPReceiveThread=NULL;
  }

  if (m_hHTTPReceiveMonitorThread)
  {
   TerminateThread(m_hHTTPReceiveMonitorThread,dwExitCode);
   CloseHandle(m_hHTTPReceiveMonitorThread);
   m_hHTTPReceiveMonitorThread=NULL;
   m_dwHTTPReceiveMonitorThreadID=0;
  }

  if(m_pdwHTTPReceiveThreadID)
  {
   delete[] m_pdwHTTPReceiveThreadID;
   m_pdwHTTPReceiveThreadID=NULL;
  }

  if(m_pBEGINEND)
  {
   delete[] m_pBEGINEND;
   m_pBEGINEND=NULL;
  }

  m_dwBEGINENDs=0;
  m_pBEGINEND=NULL;
  m_pdwHTTPReceiveThreadID=0;
  m_phHTTPReceiveThread=NULL;
  m_dwHTTPReceiveMonitorThreadID=0;
  m_hHTTPReceiveMonitorThread=NULL;

 }
public:
 CHttpDownloader()
 {
  m_dwBEGINENDs=0;
  m_pBEGINEND=NULL;
  m_pdwHTTPReceiveThreadID=0;
  m_phHTTPReceiveThread=NULL;
  m_dwHTTPReceiveMonitorThreadID=0;
  m_hHTTPReceiveMonitorThread=NULL;

  InitializeCriticalSection(&m_cs);
 }

 ~CHttpDownloader()
 {
  ExceptionHTTPReceiveMonitor(0);

  DeleteCriticalSection(&m_cs);
 }

 VOID HTTPDownLoad(LPCTSTR pstrURL,LPCTSTR pstrURLSaveAs)
 {
  try
  {
   if(pstrURL==NULL || pstrURLSaveAs==NULL)return;
   //
   m_strRequestURL=pstrURL;
   BOOL bRet=AfxParseURL(m_strRequestURL,m_dwServiceType,m_strServer,m_strObject,m_nPort); // AFXINET.H
   if(!bRet)return;
   if(AFX_INET_SERVICE_HTTP!=m_dwServiceType)return;
   //
   m_strRequestURLSaveAs=pstrURLSaveAs;
   //
   CHttpDownloader::ObtainDefURLSaveAsPath();
   //
   m_dwSourceFileSize=(DWORD)ullGetSourceFileSize(m_strServer,m_strObject,m_nPort);
   if(!m_dwSourceFileSize)return;
   //
   if(!bCalculateSegmentSize())return;
   //
   if(!m_dwBEGINENDs || !m_pBEGINEND) return;
   //
   if (m_hHTTPReceiveMonitorThread)TerminateThread(m_hHTTPReceiveMonitorThread,0);
   m_hHTTPReceiveMonitorThread=CreateThread(NULL,0,CHttpDownloader::HTTPReceiveMonitor,(LPVOID)this,0,&m_dwHTTPReceiveMonitorThreadID);
   if (m_hHTTPReceiveMonitorThread)
   {
    m_pdwHTTPReceiveThreadID=new DWORD[m_dwBEGINENDs];
    m_phHTTPReceiveThread=new HANDLE[m_dwBEGINENDs];
    //
    for(DWORD i=0;i<m_dwBEGINENDs;i++)
    {
     m_phHTTPReceiveThread[i]=NULL;
     m_pdwHTTPReceiveThreadID[i]=0;
    }
    //
    for(i=0;i<m_dwBEGINENDs;i++)
    {
     m_phHTTPReceiveThread[i]=CreateThread(NULL,0,CHttpDownloader::HTTPReceive,(LPVOID)&m_pBEGINEND[i],CREATE_SUSPENDED,&m_pdwHTTPReceiveThreadID[i]);
     if (!m_phHTTPReceiveThread[i])
     {
      TerminateThread(m_hHTTPReceiveMonitorThread,-1);
      for(i;i>=0;i--)
      {
       CloseHandle(m_phHTTPReceiveThread[i]);
       m_phHTTPReceiveThread[i]=NULL;
       m_pdwHTTPReceiveThreadID[i]=0;
      }
      SetdwBEGINENDs(0);
      break;
     }
    }
    //
    CloseHandle(m_hHTTPReceiveMonitorThread);
    m_hHTTPReceiveMonitorThread=NULL;
    m_dwHTTPReceiveMonitorThreadID=0;
   }
  }
  catch(CString e)
  {
   if(e.CompareNoCase(CHTTPDOWNLOAD_EXCEPTION)==0)
   {
    ExceptionHTTPReceiveMonitor(-1);
   }
  }
 }
};

INT main(INT argc, CHAR* argv[])
{
 CHttpDownloader httpdownloader;
 httpdownloader.HTTPDownLoad("
http://localhost:80/a.rar" ;,"c://测试.rar");
 CHAR c;
 scanf("%c",&c);
 return 0;
}

 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值