Rover12421's Blog

The End.

用Socket下载Http文件

用socket下载http文件弄了几天,总算是整理清楚了。其间遇到很多小问题,看来写的代码还是太少啊。

因为是使用socket,所以函数部分全部用了ANSI,而没有用宏了。这也是目前是用socket不太方便的地方。

说下文件写入时需注意的地方,文件路径参数,如果为NULL直接在屏幕输出,文件存在,首先清空。recv接收数据的时候,传参需注意,接收最大的长度,一定要比接收数据数组的长度小一,不然数组最后一个字节不是结束符会产生溢出。用fwrite写文件的时候,写一次就的关闭一次,fwrite不能用同一个FILE指针连续的写。而对fwrite传参也许要注意。读取数组到文件的长度,不能用strlen,也不能使用sizeof,只能用recv返回的接收数据长度。

需要注意的也就是些maxsize参数要注意的,其他的还好吧。下面贴代码:

HttpSocketDownLoad.h
  1. #pragma once
  2. #include
  3.  
  4. long fnReceive(const SOCKET m_s, char* pBuffer,const long nMaxLength);
  5. int fnResponseHeader(const SOCKET sConnectSocket, char *szResponseHeader, const int nResponseHeaderLen);
  6. bool fnSetSockOptTime(const SOCKET sConnectSocket, const int &nTime);
  7. int fnFormatRequestHeader(char *szRequestHeader, const int nRequestHeaderLen, const char *pServer, const char *pObject,
  8.     const char *pCookie = NULL, const char *pReferer = NULL, const long nFrom = 0, const long nTo = 0);
  9.  
  10. //int fnGetFileSize(const char* szRequestHeader);
  11. int fnGetFieldValue(const char *szRequestHeader, const char *szSession, char *szValue, const int nMaxLen);
  12. int fnDownloadFile(const SOCKET sConnectSocket, const long nFileSize, const char *szSavaFilePath = NULL);

 

Code.h
  1. #include "stdafx.h"
  2. #include "HttpSocketDownLoad.h"
  3.  
  4. int fnResponseHeader(const SOCKET sConnectSocket, char *szResponseHeader, const int nResponseHeaderLen)
  5. {
  6.     //获?è?HTTP请?求óμ?·μ回?í·
  7.     char c = 0;
  8.     int nIndex = 0;
  9.     BOOL bEndResponse = FALSE;
  10.     while(!bEndResponse && nIndex < nResponseHeaderLen)
  11.     {
  12.         recv(sConnectSocket, &c, 1, 0);
  13.         szResponseHeader[nIndex++] = c;
  14.         if(nIndex >= 4)
  15.         {
  16.             if(szResponseHeader[nIndex - 4] == '\r' && szResponseHeader[nIndex - 3] == '\n'
  17.                 && szResponseHeader[nIndex - 2] == '\r' && szResponseHeader[nIndex - 1] == '\n')
  18.                 bEndResponse = TRUE;
  19.         }
  20.     }
  21.     return nIndex;
  22. }
  23.  
  24. //éè置?接óê?或ò者?·¢送íμ?×?3¤ê±间?
  25. bool fnSetSockOptTime(const SOCKET sConnectSocket, const int &nTime)
  26. {
  27.     DWORD dwErr = 0;
  28.     dwErr=setsockopt(sConnectSocket, SOL_SOCKET, SO_RCVTIMEO, (char*)&nTime, sizeof(nTime));
  29.     if(dwErr)
  30.     {
  31.         return false;
  32.     }
  33.     else
  34.     {
  35.         return true;
  36.     }
  37. }
  38.  
  39. int fnFormatRequestHeader(char *szRequestHeader, const int nRequestHeaderLen, const char *pServer, const char *pObject,
  40.     const char *pCookie, const char *pReferer, const long nFrom, const long nTo)
  41. {
  42.     char szTemp[20];
  43.  
  44.     //μú1DD:·?·¨,请?求óμ?路·径?,°?±?
  45.     strcat_s(szRequestHeader, nRequestHeaderLen, "GET ");
  46.     strcat_s(szRequestHeader, nRequestHeaderLen, pObject);
  47.     strcat_s(szRequestHeader, nRequestHeaderLen, " HTTP/1.1");
  48.     strcat_s(szRequestHeader, nRequestHeaderLen, "\r\n");
  49.  
  50.     //μú2DD:主÷机ú
  51.     strcat_s(szRequestHeader, nRequestHeaderLen, "Host:");
  52.     strcat_s(szRequestHeader, nRequestHeaderLen, pServer);
  53.     strcat_s(szRequestHeader, nRequestHeaderLen, "\r\n");
  54.  
  55.     //μú3DD:
  56.     if(pReferer != NULL)
  57.     {
  58.         strcat_s(szRequestHeader, nRequestHeaderLen, "Referer:");
  59.         strcat_s(szRequestHeader, nRequestHeaderLen, pReferer);
  60.         strcat_s(szRequestHeader, nRequestHeaderLen, "\r\n");
  61.     }
  62.  
  63.     //μú4DD:接óê?μ?êy据YààDí
  64.     strcat_s(szRequestHeader, nRequestHeaderLen, "Accept:*/*");
  65.     strcat_s(szRequestHeader, nRequestHeaderLen, "\r\n");
  66.  
  67.     //μú5DD:浏ˉàà器÷ààDí
  68.     strcat_s(szRequestHeader, nRequestHeaderLen, "User-Agent:Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)");
  69.     strcat_s(szRequestHeader, nRequestHeaderLen, "\r\n");
  70.  
  71.     //μú6DD:á?接óéè置?,±£3?
  72.     strcat_s(szRequestHeader, nRequestHeaderLen, "Connection:Keep-Alive");
  73.     strcat_s(szRequestHeader, nRequestHeaderLen, "\r\n");
  74.  
  75.     //μú7DD:Cookie.
  76.     if(pCookie != NULL)
  77.     {
  78.         strcat_s(szRequestHeader, nRequestHeaderLen, "Set Cookie:0");
  79.         strcat_s(szRequestHeader, nRequestHeaderLen, pCookie);
  80.         strcat_s(szRequestHeader, nRequestHeaderLen, "\r\n");
  81.     }
  82.  
  83.     //μú8DD:请?求óμ?êy据Y起eê?×?节ú位?置?(断?μ?D?′?μ?1?键ü)
  84.     if(nFrom > 0)
  85.     {
  86.         strcat_s(szRequestHeader, nRequestHeaderLen, "Range: bytes=");
  87.         _ltoa_s(nFrom, szTemp, 10);
  88.         strcat_s(szRequestHeader, nRequestHeaderLen, szTemp);
  89.         strcat_s(szRequestHeader, nRequestHeaderLen, "-");
  90.         if(nTo > nFrom)
  91.         {
  92.             _ltoa_s(nTo, szTemp, 10);
  93.             strcat_s(szRequestHeader, nRequestHeaderLen, szTemp);
  94.         }
  95.         strcat_s(szRequestHeader, nRequestHeaderLen, "\r\n");
  96.     }
  97.  
  98.     //×?oóò?DD:空?DD
  99.     strcat_s(szRequestHeader, nRequestHeaderLen, "\r\n");
  100.     return strlen(szRequestHeader);
  101. }
  102.  
  103.  
  104. //int fnGetFileSize(const char* szRequestHeader)
  105. //{
  106. //    const char *szSession = "Content-Length";
  107. //    char szValue[10] = {0};
  108. //    const char *szFindStr = strstr(szRequestHeader, szSession);
  109. //    if (szFindStr == NULL)
  110. //    {
  111. //        return -1;
  112. //    }
  113. //    int nPos = 0;
  114. //    nPos += strlen(szSession);
  115. //    nPos += 2;
  116. //    int n = 0;
  117. //    while(szFindStr[nPos] != '\r')
  118. //    {
  119. //        szValue[n] = szFindStr[nPos];
  120. //        n++;
  121. //        nPos++;
  122. //    }  
  123. //    return atoi(szValue);
  124. //}
  125.  
  126. int fnGetFieldValue(const char *szRequestHeader, const char *szSession, char *szValue, const int nMaxLen)
  127. {
  128.     const char *szFindStr = strstr(szRequestHeader, szSession);
  129.     if (szFindStr == NULL)
  130.     {
  131.         return -1;
  132.     }
  133.     int nPos = 0;
  134.     nPos += strlen(szSession);
  135.     nPos += 2;
  136.     int n = 0;
  137.     while(szFindStr[nPos] != '\r' && n < nMaxLen)
  138.     {
  139.         szValue[n] = szFindStr[nPos];
  140.         n++;
  141.         nPos++;
  142.     }
  143.     if (szFindStr[nPos] != '\r' || szValue[nMaxLen - 1] != '\0')
  144.     {
  145.         szValue[nMaxLen - 1] = '\0';
  146.         return -1;
  147.     }
  148.     else
  149.     {
  150.         return n;
  151.     }    
  152. }
  153.  
  154.  
  155. int fnDownloadFile(const SOCKET sConnectSocket, const long nFileSize, const char *szSavaFilePath)
  156. {
  157.     long nCompletedSize = 0;
  158.     int nReceSize = 0;
  159.     char pData[1024] = {0};
  160.     FILE *fad = NULL;
  161.  
  162.     if (szSavaFilePath != NULL)
  163.     {
  164.         FILE *fd = NULL;
  165.         fopen_s(&fd, szSavaFilePath, "wb+");
  166.         if (fd == NULL)
  167.         {
  168.             return -1;
  169.         }
  170.         char s[2];
  171.         memset(s, 0, sizeof(s));
  172.         fwrite(s, 0, 0, fd);
  173.         fclose(fd);
  174.     }
  175.  
  176.     while(nCompletedSize < nFileSize)
  177.     {
  178.         memset(pData, 0, sizeof(pData));
  179.         nReceSize = recv(sConnectSocket, pData, 1023,0);      //êy×é×é′ó为a1024£?×?′ó接óê?êy据Y为a1023。£ê1ó?1024会á在ú×?oó3?现?乱ò码?
  180.         if (nReceSize == SOCKET_ERROR)
  181.         {
  182.             continue;
  183.         }
  184.  
  185.         if (szSavaFilePath == NULL)
  186.         {
  187.             printf("%s",pData);
  188.         }
  189.         else
  190.         {
  191.             fopen_s(&fad, szSavaFilePath, "ab+");
  192.             if (fad == NULL)
  193.             {
  194.                 return -1;
  195.             }
  196.             int nflen = fwrite(pData, nReceSize, 1, fad);     //fwriteμú二t个?2?êy£?2?能üê1ó?sizeofoístrlen计?算?3¤度è£?recv·μ回?μ?3¤度è2?ê?正yè·μ?
  197.             if (nflen != 1)
  198.             {
  199.                 fclose(fad);
  200.                 return -1;
  201.             }      
  202.             fclose(fad);
  203.         }
  204.         nCompletedSize += nReceSize;
  205.         //printf("nReceSize=%d\tnCompletedSize=%ld.\n", nReceSize, nCompletedSize);        
  206.     }
  207.     return nCompletedSize;
  208. }

 

testHttpSocket.h
  1. #include "stdafx.h"
  2.     #include //°üo?′?í·文?件t2?能üê1ó?默?è?μ?/MDd,DT改?为a/MTd
  3. #include "HttpSocketDownLoad.h"
  4.  
  5. int _tmain(int argc, _TCHAR* argv[])
  6. {
  7.     //LPCTSTR lpName = _T("http://www.baidu.com");    //±?D?加ó正yè·μ?D-òéí·£?·?则ò2?能ü下?载?
  8.     LPCTSTR lpName = _T("https://www.rover12421.com/sitemap.xml.gz");
  9.     
  10.     CString strServer = _T("");
  11.     CString strObject = _T("");
  12.     unsigned short nPort = 0;
  13.     DWORD dwServiceType = 0;
  14.     long nLength = 0;
  15.     AfxParseURL(lpName, dwServiceType, strServer, strObject, nPort);
  16.  
  17.     struct protoent *ppe;
  18.     ppe = getprotobyname("tcp");    //D-òé名?2?区?·?′óD?D′
  19.  
  20.     int nRequestHeaderLen = 1024;
  21.     char szRequestHeader[1024];
  22.     memset(szRequestHeader, '\0', nRequestHeaderLen);
  23.     
  24.     nLength = fnFormatRequestHeader(szRequestHeader, nRequestHeaderLen, CT2A(strServer), CT2A(strObject));
  25.     printf("FormatRequestHeader:\n%s\nnLength = %d\n", szRequestHeader, nLength);
  26.  
  27.     hostent *m_phostent = gethostbyname(CT2A(strServer));    
  28.     struct in_addr ip_addr;
  29.     memcpy(&ip_addr, m_phostent->h_addr_list[0], 4);    //h_addr_list[0]à?4个?×?节ú,每?个?×?节ú8位?
  30.  
  31.     struct sockaddr_in destaddr;
  32.     memset((void *)&destaddr, 0 ,sizeof(destaddr));
  33.     destaddr.sin_family = AF_INET;
  34.     destaddr.sin_port = htons(nPort);
  35.     destaddr.sin_addr = ip_addr;
  36.     char m_ipaddr[256] = {0};
  37.     //±£′?主÷机úμ?IPμ?址·×?·?′?
  38.     sprintf_s(m_ipaddr, "%d.%d.%d.%d", destaddr.sin_addr.S_un.S_un_b.s_b1,
  39.         destaddr.sin_addr.S_un.S_un_b.s_b2, destaddr.sin_addr.S_un.S_un_b.s_b3,
  40.         destaddr.sin_addr.S_un.S_un_b.s_b4);
  41.     printf("IP = %s\n", m_ipaddr);
  42.  
  43.     SOCKET m_socket = socket(AF_INET, SOCK_STREAM, ppe->p_proto);
  44.     if (m_socket == INVALID_SOCKET)
  45.     {
  46.         return 0;
  47.     }
  48.  
  49.     if (connect(m_socket, (struct sockaddr*)&destaddr, sizeof(destaddr)) == SOCKET_ERROR)
  50.     {
  51.         return 0;
  52.     }
  53.  
  54.     if (send(m_socket, szRequestHeader, nLength, 0) == SOCKET_ERROR)
  55.     {
  56.         closesocket(m_socket);
  57.         return 0;
  58.     }
  59.  
  60.     char szResponseHeader[1024] = {0};
  61.     int nResponseHeaderSize = fnResponseHeader(m_socket, szResponseHeader, sizeof(szResponseHeader));
  62.  
  63.     printf("\nResponseHeader:\n%s\n", szResponseHeader);
  64.     printf("ResponseHeaderSize = %d\n", nResponseHeaderSize);
  65.  
  66.     //éè置?接óê?或ò者?·¢送íμ?×?3¤ê±间?
  67.     int nTime = 1000;
  68.     fnSetSockOptTime(m_socket, nTime);
  69.    
  70.     char szValue[10] = {0};
  71.     long nFileSize = 0;
  72.     nFileSize = fnGetFieldValue(szResponseHeader, "Content-Length", szValue, sizeof(szValue));
  73.     if (nFileSize <= 0)
  74.     {
  75.         printf("Get File Size Faild.\n");
  76.     }
  77.     nFileSize = atol(szValue);
  78.     printf("nFileSize = %ld\n", nFileSize);
  79.     printf("\nDownloadFile:\n");
  80.     char szFilePath[] = "z:\\sitemap.xml.gz";
  81.     int nDownloadSize = fnDownloadFile(m_socket, nFileSize, szFilePath);
  82.     printf("\nnDownloadSize = %d.\n", nDownloadSize);
  83.     closesocket(m_socket);
  84.     return 0;
  85. }

测试文件效果如下:

image

Comments