发一个多线程通过 HTTP 下载文件的类(Linux下的实现)

来源:互联网 发布:mac打不开flash网站 编辑:程序博客网 时间:2024/05/07 09:06

多线程下载文件这个话题已经是老汤了。

在HTTP协议1.1中,允许通过增加一个HTTP Header“Range”来指定下载文件的区间。
所以一般的做法都是:

  • 首先获取到文件大小(通过Content-Length)
  • 开一个线程池在进行分块下载。



而在具体怎么实现的流程上,还是有差别的。

1. 标准的做法是:首先用一个线程发送HTTP GET指令,服务器会返回Content-Length,并能够根据协议判断出服务器是否支持Range。如果支持Range,则调配其它线程对后续部分分块下载。第一个线程继续下载第1块。

2. 还一种做法,首先发送HTTP HEAD指令,通过返回的Content-Length进行分块,调配线程进行下载。

这里提供一个类,属于第2种。
为了提高IO性能,类中可以使用内存映射文件方式进行操作。

  1. #ifndef CHTTPFILEDOWNLOADER_H_
  2. #define CHTTPFILEDOWNLOADER_H_
  3. #include "Generic.h"
  4. class CHttpFileDownloader {
  5. public:
  6.     CHttpFileDownloader();
  7.     virtual ~CHttpFileDownloader();
  8.     bool downloadUrlToFile( const char * lpszUrl, const char * lpszFile);
  9.     bool waitForCompletion(void);
  10. private:
  11.     string              m_strLocalFile;
  12.     pthread_t           m_lLeaderThread;
  13.     struct sockaddr_in  m_stServerAddr;
  14.     char                m_szResourceURI[1024];
  15.     char                m_szDomain[1024];
  16.     char                m_szHost[1024];
  17.     char                m_szUrl[1024];
  18.     sem_t               m_stDownSem;
  19.     pthread_mutex_t     m_stDownloadThreadMutex;
  20.     int                 m_nDownloadThreadCnt;
  21.     bool                m_bFailed;
  22.     sem_t               m_stCompleteSem;
  23.     bool                m_bSuccess;
  24.     static void * leaderThread(void* param);
  25.     static void * downloadThread(void* param);
  26.     bool downloadProcess(void);
  27.     void downloadBlock(unsigned char * pMemory, int nRangeStart, int nRangeSize);
  28.     bool sendBuffer( int nSocket, char * pBuf, int nSize);
  29.     bool sendStringStream(int nSocket, stringstream & oStream);
  30.     int recvStringStream(int nSocket, stringstream & oStream);
  31.     std::vector<string> parseResponse(string strResponse);
  32.     bool isHttpStatusSuccess(string & strHttpResponse);
  33.     string getHeaderValueByName(const char * lpszHeader, std::vector<string> & vItems);
  34. };
  35. #endif /* CHTTPFILEDOWNLOADER_H_ */
  1. /*
  2.  * CHttpFileDownloader.cpp
  3.  *
  4.  *  Created on: 2008-12-15
  5.  *      Author: root
  6.  */
  7. #include "Generic.h"
  8. #include "CMainApp.h"
  9. #include "CHttpFileDownloader.h"
  10. // 64K
  11. #define DOWNLOAD_BLOCK_SIZE  1024*512
  12. #define MAX_DOWNLOAD_THREAD  5
  13. typedef struct _tagDownloadTask
  14. {
  15.     CHttpFileDownloader *   pThis;
  16.     unsigned char *         pStart;
  17.     int                     nSize;
  18.     int                     nRangeStart;
  19. }tagDownloadTask, *LPDownloadTask;
  20. CHttpFileDownloader::CHttpFileDownloader() {
  21.     sem_init( &m_stCompleteSem, 0, 0);
  22. }
  23. CHttpFileDownloader::~CHttpFileDownloader() {
  24.     sem_destroy( &m_stCompleteSem );
  25. }
  26. bool CHttpFileDownloader::sendStringStream(int nSocket, stringstream & oStream)
  27. {
  28.     int nSize = oStream.str().length() * sizeof(char);
  29.     char * pBuffer = new char[nSize];
  30.     memcpy( pBuffer, oStream.str().c_str(), nSize);
  31.     int nSent = 0;
  32.     while(nSent < nSize)
  33.     {
  34.         int nRet = send( nSocket, (char*)(pBuffer + nSent), nSize - nSent, 0);
  35.         if( nRet == -1 )
  36.             break;
  37.         nSent += nRet;
  38.     }
  39.     delete [] pBuffer;
  40.     return (nSent == nSize);
  41. }
  42. bool CHttpFileDownloader::sendBuffer( int nSocket, char * pBuf, int nSize)
  43. {
  44.     int nSent = 0;
  45.     while(nSent < nSize)
  46.     {
  47.         int nRet = send( nSocket, (char*)(pBuf + nSent), nSize - nSent, 0);
  48.         if( nRet == -1 )
  49.             break;
  50.         nSent += nRet;
  51.     }
  52.     return (nSent == nSize);
  53. }
  54. int CHttpFileDownloader::recvStringStream(int nSocket, stringstream & oStream)
  55. {
  56.     int nReceived = 0;
  57.     while(true)
  58.     {
  59.         char szBuf[1025] = {0};
  60.         int nRet = recv( nSocket, szBuf, 1024, 0);
  61.         if( nRet == 0 )
  62.             break;
  63.         if( nRet < 0 )
  64.             break;
  65.         oStream << szBuf;
  66.         nReceived += nRet;
  67.         if( oStream.str().find("/r/n/r/n") != string::npos )
  68.             break;
  69.     }
  70.     return nReceived;
  71. }
  72. std::vector<string> CHttpFileDownloader::parseResponse(string strResponse)
  73. {
  74.     std::vector<string> vItems;
  75.     size_t nLast = strResponse.find("/r/n/r/n");
  76.     if( nLast >= strResponse.length() )
  77.         return vItems;
  78.     size_t nPos = 0;
  79.     while(nPos < nLast)
  80.     {
  81.         size_t nFind = strResponse.find("/r/n", nPos);
  82.         if( nFind > nLast )
  83.             break;
  84.         vItems.push_back( strResponse.substr( nPos, nFind-nPos));
  85.         nPos = nFind + 2;
  86.     }
  87.     return vItems;
  88. }
  89. bool CHttpFileDownloader::isHttpStatusSuccess(string & strHttpResponse)
  90. {
  91.     size_t nBegin = strHttpResponse.find(' ');
  92.     if( nBegin > strHttpResponse.length() )
  93.         return false;
  94.     size_t nEnd = strHttpResponse.find_last_of(' ');
  95.     if( nEnd > strHttpResponse.length() )
  96.         return false;
  97.     string strStatusCode = strHttpResponse.substr( nBegin+1, nEnd-nBegin-1);
  98.     int nStatusCode = atoi(strStatusCode.c_str());
  99.     return (nStatusCode >= 200 && nStatusCode < 300);
  100. }
  101. string CHttpFileDownloader::getHeaderValueByName(const char * lpszHeader, std::vector<string> & vItems)
  102. {
  103.     string strHeader = lpszHeader;
  104.     std::transform( strHeader.begin(), strHeader.end(), strHeader.begin(), (int (*)(int))std::tolower);
  105.     strHeader.append(":");
  106.     string strValue = "";
  107.     std::vector<string>::iterator iter;
  108.     for( iter = vItems.begin(); iter != vItems.end(); iter++)
  109.     {
  110.         string strItem = *iter;
  111.         std::transform( strItem.begin(), strItem.end(), strItem.begin(), (int (*)(int))std::tolower);
  112.         if( strItem.find(strHeader) != 0 )
  113.             continue;
  114.         strValue = strItem.substr( strHeader.length() );
  115.         break;
  116.     }
  117.     return strValue.erase( 0, strValue.find_first_not_of(' '));
  118. }
  119. bool CHttpFileDownloader::downloadUrlToFile( const char * lpszUrl, const char * lpszFile)
  120. {
  121.     memset( m_szUrl, 0, 1024);
  122.     memcpy( m_szUrl, lpszUrl, strlen(lpszUrl));
  123.     m_strLocalFile = lpszFile;
  124.     // create thread
  125.     int nErr = pthread_create( &m_lLeaderThread
  126.             , NULL
  127.             , &leaderThread
  128.             , this
  129.             );
  130.     if( nErr != 0 )
  131.     {
  132.         CMainApp::getSingleton()->log("Error: pthread_create download leader thread failed. Return=%d, Message=%s"
  133.                 , nErr
  134.                 , strerror(nErr)
  135.                 );
  136.         return false;
  137.     }
  138.     return true;
  139. }
  140. bool CHttpFileDownloader::waitForCompletion(void)
  141. {
  142.     sem_wait(&m_stCompleteSem);
  143.     return m_bSuccess;
  144. }
  145. void * CHttpFileDownloader::leaderThread(void* param)
  146. {
  147.     CHttpFileDownloader * pThis = static_cast<CHttpFileDownloader*>(param);
  148.     CMainApp::getSingleton()->log("Info: download file /"%s/" start..."
  149.                         , pThis->m_szUrl
  150.                         );
  151.     pThis->m_bSuccess = pThis->downloadProcess();
  152.     sem_post( &pThis->m_stCompleteSem );
  153.     CMainApp::getSingleton()->log("Info: download file /"%s/" %s..."
  154.                             , pThis->m_szUrl
  155.                             , pThis->m_bSuccess ? "success" : "failed"
  156.                             );
  157.     return NULL;
  158. }
  159. bool CHttpFileDownloader::downloadProcess(void)
  160. {
  161.     // parse the url and port
  162.     string strUrl = m_szUrl;
  163.     std::transform( strUrl.begin(), strUrl.end(), strUrl.begin(), (int (*)(int))std::tolower);
  164.     size_t uFind = strUrl.find("http://");
  165.     if( uFind != 0 )
  166.     {
  167.         CMainApp::getSingleton()->log("Error: Invalid URL:%s"
  168.             , m_szUrl
  169.             );
  170.         return false;
  171.     }
  172.     int nLen = string("http://").length();
  173.     uFind = strUrl.find('/', nLen);
  174.     if( uFind > strUrl.length() )
  175.     {
  176.         CMainApp::getSingleton()->log("Error: Invalid URL:%s"
  177.             , m_szUrl
  178.             );
  179.         return false;
  180.     }
  181.     strUrl = m_szUrl;
  182.     string strHost = strUrl.substr( nLen, uFind - nLen);
  183.     string strResourceURI = strUrl.substr(uFind);
  184.     string strDomain = strHost;
  185.     uint uPort = 80;
  186.     uFind = strHost.find(':');
  187.     if( uFind < strHost.length() )
  188.     {
  189.         strDomain = strHost.substr( 0, uFind);
  190.         uPort = atoi( strHost.substr(uFind+1).c_str() );
  191.     }
  192.     struct hostent * pHostent = gethostbyname(strDomain.c_str());
  193.     if( pHostent == NULL )
  194.     {
  195.         CMainApp::getSingleton()->log("Error: failed to resolve the IP address for the URL:%s"
  196.                         , m_szUrl
  197.                         );
  198.         return false;
  199.     }
  200.     memset( &m_stServerAddr, 0, sizeof(m_stServerAddr));
  201.     m_stServerAddr.sin_family = AF_INET;
  202.     m_stServerAddr.sin_port = htons((short)uPort);
  203.     memcpy( (char*)&m_stServerAddr.sin_addr.s_addr, pHostent->h_addr_list[0], pHostent->h_length);
  204.     int sock = socket( AF_INET, SOCK_STREAM, 0);
  205.     if( sock == -1 )
  206.     {
  207.         CMainApp::getSingleton()->log("Error: socket failed. error=%s"
  208.             , strerror(errno)
  209.             );
  210.         return false;
  211.     }
  212.     memset( m_szResourceURI, 0, 1024);
  213.     memcpy( m_szResourceURI, strResourceURI.c_str(), strlen(strResourceURI.c_str()));
  214.     memset( m_szHost, 0, 1024);
  215.     memcpy( m_szHost, strHost.c_str(), strlen(strHost.c_str()));
  216.     memset( m_szDomain, 0, 1024);
  217.     memcpy( m_szDomain, strDomain.c_str(), strlen(strDomain.c_str()));
  218.     // populate the HTTP HEAD request
  219.     stringstream strHttp;
  220.     strHttp << "HEAD " << m_szResourceURI << " HTTP/1.1/r/n";
  221.     strHttp << "User-Agent: Mozilla/4.0 (compatible; MSIE 5.00; Windows 98)/r/n";
  222.     strHttp << "Host:" << m_szHost << "/r/n";
  223.     strHttp << "Cache-Control: no-cache/r/n";
  224.     strHttp << "Pragma: no-cache/r/n";
  225.     strHttp << "Connection: Keep-Alive/r/n";
  226.     strHttp << "Accept: */*/r/n";
  227.     strHttp << "/r/n";
  228.     int nRet = connect( sock
  229.             , (struct sockaddr *)&m_stServerAddr
  230.             , sizeof(struct sockaddr)
  231.             );
  232.     if( nRet == -1 )
  233.     {
  234.         CMainApp::getSingleton()->log("Error: failed to connect to URL:%s"
  235.                 , m_szUrl
  236.                 );
  237.         return false;
  238.     }
  239.     struct timeval tv = {0};
  240.     tv.tv_sec = 15;
  241.     if (setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv,  sizeof(tv)))
  242.     {
  243.         CMainApp::getSingleton()->log("Error: setsockopt failed(1). error=%s"
  244.                 , strerror(errno)
  245.                 );
  246.         return false;
  247.     }
  248.     if( !sendStringStream( sock, strHttp) )
  249.     {
  250.         CMainApp::getSingleton()->log("Error: failed to send the HTTP HEAD request to URL:%s"
  251.                 , m_szUrl
  252.                 );
  253.         return false;
  254.     }
  255.     stringstream strResponse;
  256.     recvStringStream( sock, strResponse);
  257.     shutdown(sock, SHUT_RDWR);
  258.     close(sock);
  259.     // parse the response
  260.     std::vector<string> vItems = parseResponse(strResponse.str());
  261.     if( vItems.size() == 0 )
  262.     {
  263.         CMainApp::getSingleton()->log("Error: the HTTP HEAD response contains nothing. URL:%s"
  264.             , m_szUrl
  265.             );
  266.         return false;
  267.     }
  268.     if( !isHttpStatusSuccess(vItems[0]) )
  269.     {
  270.         CMainApp::getSingleton()->log("Error: %s. URL:%s"
  271.             , vItems[0].c_str()
  272.             , m_szUrl
  273.             );
  274.         return false;
  275.     }
  276.     string strContentLen = getHeaderValueByName( "Content-Length", vItems);
  277.     if( strContentLen.length() == 0 )
  278.     {
  279.         CMainApp::getSingleton()->log("Error: Invalid Content-Length in HTTP HEAD response. URL:%s"
  280.             , m_szUrl
  281.             );
  282.         return false;
  283.     }
  284.     int nContentLength = atoi(strContentLen.c_str());
  285.     // create file
  286.     std::ofstream outStream;
  287.     outStream.open( m_strLocalFile.c_str(), ios_base::out | ios_base::binary | ios_base::trunc);
  288.     outStream.seekp(nContentLength-1);
  289.     outStream.put('/0');
  290.     outStream.close();
  291.     int fd = open( m_strLocalFile.c_str(), O_RDWR);
  292.     if( fd == -1 )
  293.     {
  294.         CMainApp::getSingleton()->log("Error: can not create file /"%s/". %s"
  295.             , m_strLocalFile.c_str()
  296.             , strerror(errno)
  297.             );
  298.         return false;
  299.     }
  300.     unsigned char * pMemory = (unsigned char *)mmap(NULL, nContentLength, PROT_WRITE, MAP_SHARED | MAP_POPULATE | MAP_NONBLOCK, fd, 0);
  301.     close(fd);
  302.     if( pMemory == MAP_FAILED )
  303.     {
  304.         CMainApp::getSingleton()->log("Error: failed to map the file /"%s/" into memory; size=%d; error=%s"
  305.             , m_strLocalFile.c_str()
  306.             , nContentLength
  307.             , strerror(errno)
  308.             );
  309.         return false;
  310.     }
  311.     mlock(pMemory, nContentLength);
  312.     // create thread
  313.     sem_init( &m_stDownSem, 0, MAX_DOWNLOAD_THREAD);
  314.     pthread_mutex_init( &m_stDownloadThreadMutex, NULL);
  315.     m_bFailed = false;
  316.     int nDownloadLength = 0;
  317.     m_nDownloadThreadCnt = 0;
  318.     while(true)
  319.     {
  320.         sem_wait(&m_stDownSem);
  321.         if( nDownloadLength >= nContentLength ||
  322.             m_bFailed )
  323.         {
  324.             if( m_nDownloadThreadCnt == 0 )
  325.                 break;
  326.             else
  327.                 continue;
  328.         }
  329.         LPDownloadTask pTask = (LPDownloadTask)malloc(sizeof(tagDownloadTask));
  330.         pTask->pStart = (unsigned char*)(pMemory + nDownloadLength);
  331.         pTask->nSize = ((DOWNLOAD_BLOCK_SIZE + nDownloadLength) > nContentLength)
  332.         ? (nContentLength - nDownloadLength) : DOWNLOAD_BLOCK_SIZE;
  333.         pTask->nRangeStart = nDownloadLength;
  334.         pTask->pThis = this;
  335.         nDownloadLength += pTask->nSize;
  336.         // create thread
  337.         pthread_t lThread;
  338.         int nErr = pthread_create( &lThread
  339.                 , NULL
  340.                 , &downloadThread
  341.                 , pTask
  342.                 );
  343.         if( nErr != 0 )
  344.         {
  345.             CMainApp::getSingleton()->log("Error: pthread_create download thread failed. Error=%d, Message=%s"
  346.                     , nErr
  347.                     , strerror(nErr)
  348.                     );
  349.             m_bFailed = true;
  350.         }
  351.         else
  352.         {
  353.             pthread_mutex_lock(&m_stDownloadThreadMutex);
  354.             m_nDownloadThreadCnt ++;
  355.             pthread_mutex_unlock(&m_stDownloadThreadMutex);
  356.         }
  357.     }
  358.     pthread_mutex_destroy( &m_stDownloadThreadMutex);
  359.     sem_destroy(&m_stDownSem);
  360.     if( msync( pMemory, nContentLength, MS_SYNC) == -1 )
  361.     {
  362.         CMainApp::getSingleton()->log("Error: failed to msync the file /"%s/" from memory; size=%d; error=%s"
  363.             , m_strLocalFile.c_str()
  364.             , nContentLength
  365.             , strerror(errno)
  366.             );
  367.         m_bFailed = true;
  368.     }
  369.     munlock(pMemory, nContentLength);
  370.     munmap( pMemory, nContentLength);
  371.     return !m_bFailed;
  372. }
  373. void * CHttpFileDownloader::downloadThread(void* param)
  374. {
  375.     LPDownloadTask pTask = static_cast<LPDownloadTask>(param);
  376.     pTask->pThis->downloadBlock( pTask->pStart
  377.             , pTask->nRangeStart
  378.             , pTask->nSize
  379.             );
  380.     pthread_mutex_lock(&(pTask->pThis->m_stDownloadThreadMutex));
  381.     pTask->pThis->m_nDownloadThreadCnt --;
  382.     pthread_mutex_unlock(&(pTask->pThis->m_stDownloadThreadMutex));
  383.     sem_post(&(pTask->pThis->m_stDownSem));
  384.     free(pTask);
  385.     return NULL;
  386. }
  387. void CHttpFileDownloader::downloadBlock(unsigned char * pMemory, int nRangeStart, int nRangeSize)
  388. {
  389.     CMainApp::getSingleton()->log("Info: download block /"%s/" [%08d-%08d] start..."
  390.                                 , m_szUrl
  391.                                 , nRangeStart
  392.                                 , nRangeStart + nRangeSize - 1
  393.                                 );
  394.     int nReceived = 0;
  395.     int nErrorTimes = 0;
  396.     while( nReceived < nRangeSize && nErrorTimes < 5 && !m_bFailed )
  397.     {
  398.         int nSocket = socket( AF_INET, SOCK_STREAM, 0);
  399.         if( nSocket == -1 )
  400.         {
  401.             nErrorTimes++;
  402.             continue;
  403.         }
  404.         int nRet = connect( nSocket
  405.                 , (struct sockaddr *)&m_stServerAddr
  406.                 , sizeof(struct sockaddr)
  407.                 );
  408.         if( nRet == -1 )
  409.         {
  410.             nErrorTimes++;
  411.             CMainApp::getSingleton()->log("Error: failed to connect to URL:%s"
  412.                     , m_szUrl
  413.                     );
  414.             continue;
  415.         }
  416.         {
  417.             struct timeval tv = {0};
  418.             tv.tv_sec = 15;
  419.             if (setsockopt(nSocket, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv,  sizeof(tv)))
  420.             {
  421.                 nErrorTimes++;
  422.                 CMainApp::getSingleton()->log("Error: setsockopt failed(2). error=%s"
  423.                         , strerror(errno)
  424.                         );
  425.                 continue;
  426.             }
  427.         }
  428.         {
  429.             char szRequest[4096] = {0};
  430.             sprintf( szRequest, "GET %s HTTP/1.1/r/n"
  431.                     "User-Agent: Mozilla/4.0 (compatible; MSIE 5.00; Windows 98)/r/n"
  432.                     "Host: %s/r/n"
  433.                     "Cache-Control: no-cache/r/n"
  434.                     "Pragma: no-cache/r/n"
  435.                     "Connection: Keep-Alive/r/n"
  436.                     "Accept: */*/r/n"
  437.                     "Range: bytes=%d-%d/r/n"
  438.                     "/r/n"
  439.                     , m_szResourceURI
  440.                     , m_szHost
  441.                     , nRangeStart+nReceived
  442.                     , nRangeStart+nRangeSize-1
  443.                     );
  444.             if( !sendBuffer( nSocket, szRequest, strlen(szRequest)) )
  445.             {
  446.                 shutdown(nSocket, SHUT_RDWR);
  447.                 close(nSocket);
  448.                 CMainApp::getSingleton()->log("Error: failed to send the HTTP GET request to URL:%s"
  449.                         , m_szUrl
  450.                         );
  451.                 nErrorTimes++;
  452.                 continue;
  453.             }
  454.         }
  455.         char szBuf[1024] = {0};
  456.         nRet = recv( nSocket, szBuf, 1024, 0);
  457.         if( nRet <= 0 )
  458.         {
  459.             shutdown(nSocket, SHUT_RDWR);
  460.             close(nSocket);
  461.             CMainApp::getSingleton()->log("Error: recv failed(1). return code=%d, error=%s, URL=%s"
  462.                     , nRet
  463.                     , strerror(errno)
  464.                     , m_szUrl
  465.                     );
  466.             nErrorTimes++;
  467.             continue;
  468.         }
  469.         string strHttpResponse;
  470.         int nRemain = 0;
  471.         int nIndex = 0;
  472.         for(nIndex = 0; nIndex < nRet; nIndex++)
  473.         {
  474.             if( szBuf[nIndex] == '/r' &&
  475.                 szBuf[nIndex+1] == '/n' &&
  476.                 szBuf[nIndex+2] == '/r' &&
  477.                 szBuf[nIndex+3] == '/n' )
  478.             {
  479.                 char szTemp[1025] = {0};
  480.                 memcpy( szTemp, szBuf, nIndex+4);
  481.                 strHttpResponse = szTemp;
  482.                 nRemain = nRet -(nIndex+4);
  483.                 break;
  484.             }
  485.         }
  486.         if( strHttpResponse.length() == 0 )
  487.         {
  488.             shutdown(nSocket, SHUT_RDWR);
  489.             close(nSocket);
  490.             nErrorTimes++;
  491.             CMainApp::getSingleton()->log("Error: the response does not contain a HTTP header(1), URL:%s"
  492.                     , m_szUrl
  493.                     );
  494.             continue;
  495.         }
  496.         std::vector<string> vItems = parseResponse(strHttpResponse);
  497.         if( vItems.size() == 0 )
  498.         {
  499.             shutdown(nSocket, SHUT_RDWR);
  500.             close(nSocket);
  501.             nErrorTimes++;
  502.             CMainApp::getSingleton()->log("Error: the response does not contain a HTTP header(2). URL:%s"
  503.                 , m_szUrl
  504.                 );
  505.             continue;
  506.         }
  507.         if( !isHttpStatusSuccess(vItems[0]) )
  508.         {
  509.             shutdown(nSocket, SHUT_RDWR);
  510.             close(nSocket);
  511.             nErrorTimes++;
  512.             CMainApp::getSingleton()->log("Error: %s. URL:%s"
  513.                 , vItems[0].c_str()
  514.                 , m_szUrl
  515.                 );
  516.             continue;
  517.         }
  518.         if( nRemain > 0 )
  519.         {
  520.             memcpy( (unsigned char*)(pMemory+nReceived), &(szBuf[nIndex+4]), nRemain);
  521.             nReceived += nRemain;
  522.         }
  523.         while( (nReceived < nRangeSize) && !m_bFailed )
  524.         {
  525.             nRet = recv( nSocket, (unsigned char*)(pMemory+nReceived), nRangeSize - nReceived, 0);
  526.             if( nRet <= 0 )
  527.             {
  528.                 CMainApp::getSingleton()->log("Error: recv falied(2). return code=%d, error=%s, URL=%s"
  529.                         , nRet
  530.                         , strerror(errno)
  531.                         , m_szUrl
  532.                         );
  533.                 nErrorTimes++;
  534.                 break;
  535.             }
  536.             nReceived += nRet;
  537.         }
  538.         shutdown(nSocket, SHUT_RDWR);
  539.         close(nSocket);
  540.     }// while
  541.     m_bFailed = m_bFailed ? m_bFailed : (nReceived != nRangeSize);
  542.     CMainApp::getSingleton()->log("Info: download block /"%s/" [%08d-%08d] %s."
  543.                             , m_szUrl
  544.                             , nRangeStart
  545.                             , nRangeStart + nRangeSize - 1
  546.                             , (nReceived != nRangeSize) ? "Failed" : "Success"
  547.                             );
  548. }

 

原创粉丝点击