int httpdownload(const char* url, const char* localfile) { const char* pSplitStr = NULL; const char* pTemp = NULL; const char* pLastPos = NULL; const char* pEndPos = NULL; int iTempRet = 0; const int iTempBufSize = 1024; const int iUrlBufSize = 2084; const int iRecvBufSize = 64*1024; const int iHttpHeaderBufSize = 16*1024; bool bUseBreakMode = false; // 是否启用断点续传 char* pHost = NULL; char* pRefer = NULL; int iHostPort = 80; char* pFileUrl = NULL; ULONG ulNetIp = 0; struct hostent* lpHostent = NULL; SOCKET scSocket = INVALID_SOCKET; sockaddr_in siSockaddr; char* pHttpRequest = NULL; char* pHttpResponse = NULL; LPBYTE lpBufTemp = (LPBYTE)NULL; DWORD dwDataLen = 0; char* pTempBuf = NULL; char* pHeaderEndPos = NULL; DWORD dwSentTotal = 0; bool bRet = true; int iRecv = 0; int iRecvedTotal = 0; int iRetCode = 0; long lFileOffset = 0; int iTotalDataSize = 0; int iRecvedFileBytes = 0; FILE* fpTempFile = NULL; FILE* fpBreakFile = NULL; char* pBreakFileUrl = NULL; char* pTempFileUrl = NULL; int i = 0; WSADATA wdData; // if ((strlen(url) == 0) || (strlen(url) > 2083) || (url == NULL)) { return 1; // 无效的参数 } if ((strlen(localfile) == 0) || (localfile == NULL)) { return 1; // 无效的参数 } // iTempRet = WSAStartup(0x0202, &wdData); if (iTempRet != 0) { return 2; } // pHost = (char*)malloc(iUrlBufSize); pRefer = (char*)malloc(iUrlBufSize); pFileUrl = (char*)malloc(iUrlBufSize); pHttpRequest = (char*)malloc(iHttpHeaderBufSize); pHttpResponse = (char*)malloc(iRecvBufSize); pTempBuf = (char*)malloc(iTempBufSize); pBreakFileUrl = (char*)malloc(iTempBufSize); pTempFileUrl = (char*)malloc(iTempBufSize); // __try { if (pHost == NULL || pRefer == NULL || pFileUrl == NULL || pHttpRequest == NULL || pHttpResponse == NULL || pTempBuf == NULL || pBreakFileUrl == NULL || pTempFileUrl == NULL) { return 3; } memset(pHost, 0, iUrlBufSize); memset(pRefer, 0, iUrlBufSize); memset(pFileUrl, 0, iUrlBufSize); memset(pHttpRequest, 0, iHttpHeaderBufSize); memset(pHttpResponse, 0, iRecvBufSize); memset(pTempBuf, 0, iTempBufSize); memset(pBreakFileUrl, 0, iTempBufSize); tagDown: // 分割URL,http://www.aaa.com/aaa/aaa或者http://www.aaa.com/aaa/aaa?test pSplitStr = "http://"; iTempRet = strnicmp(url, pSplitStr, strlen(pSplitStr)); if (iTempRet != 0) { return 4; // 无效的地址 } // 得到主机名 pTemp = url + strlen(pSplitStr); // 查找主机结束符 pLastPos = strchr(pTemp, '/'); if (pLastPos == NULL) { strcpy(pHost, pTemp); pFileUrl[0] = '/'; } else { strncpy(pHost, pTemp, pLastPos-pTemp); strcpy(pFileUrl, pLastPos); } // 查找端口 pLastPos = strchr(pHost, ':'); if (pLastPos == NULL) { iHostPort = 80; } else { iHostPort = atoi(pLastPos+1); //*pLastPos = '\0'; } // 解析主机 lpHostent = gethostbyname(pHost); if (lpHostent == NULL) { return 4; } if (lpHostent->h_length < 1) { return 4; } // ulNetIp = *(ULONG*)(lpHostent->h_addr_list[0]); // 连接主机 scSocket = socket(AF_INET, SOCK_STREAM, 0); if (scSocket == INVALID_SOCKET) { return 5; } siSockaddr.sin_family = AF_INET; siSockaddr.sin_addr.S_un.S_addr = ulNetIp; siSockaddr.sin_port = htons(iHostPort); // for (i=0; ;) { iTempRet = connect(scSocket, (const struct sockaddr*)&siSockaddr, sizeof(siSockaddr)); if (iTempRet != 0) { if (++i < 10) { Sleep(1000); continue; } return 6; } break; } // 构建HTTP头 #define FORMAT_HTTP_GET_REQUEST "GET %s HTTP/1.1\r\n"\ "Accept: */*\r\n"\ "Accept-Language: zh-CN\r\n"\ "User-Agent: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; WOW64; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; InfoPath.2)\r\n"\ "Host: %s\r\n"\ "Cache-Control: no-cache\r\n"\ "Expires: 0\r\n"\ "Connection: Keep-Alive\r\n"\ "Referer: %s\r\n"\ "Range: bytes=%d-\r\n"\ "\r\n" // sprintf(pHttpRequest, FORMAT_HTTP_GET_REQUEST, pFileUrl, pHost, pRefer, lFileOffset); // 发送请求 lpBufTemp = (LPBYTE)pHttpRequest; dwDataLen = strlen(pHttpRequest); dwSentTotal = 0; bRet = true; while (dwSentTotal < dwDataLen) { int iSent = send(scSocket, (const char*)(lpBufTemp+dwSentTotal), dwDataLen-dwSentTotal, 0); if (iSent == 0) { bRet = false; break; } else if (iSent == SOCKET_ERROR) { bRet = false; break; } else { dwSentTotal += iSent; } } // 接收HTTP返回数据 iRecvedTotal = 0; while (true) { iRecv = recv(scSocket, pHttpResponse+iRecvedTotal, iRecvBufSize-iRecvedTotal, 0); if (iRecv == 0 || iRecv == SOCKET_ERROR) { return 7; } iRecvedTotal += iRecv; // 连续找两个\r\n表示结束 pSplitStr = "\r\n\r\n"; pHeaderEndPos = strstr(pHttpResponse, pSplitStr); if (pHeaderEndPos != NULL) { pHeaderEndPos += strlen(pSplitStr); break; } if (iRecvBufSize == iRecvedTotal) { return 8; } } // 解析返回 pLastPos = strchr(pHttpResponse, ' '); if (pLastPos == NULL) { return 9; } pLastPos += 1; pEndPos = strstr(pLastPos, "\r\n"); strncpy(pTempBuf, pLastPos, pEndPos-pLastPos); pLastPos = strchr(pTempBuf, ' '); if (pLastPos != NULL) { pTempBuf[pLastPos-pTempBuf] = '\0'; } iRetCode = atoi(pTempBuf); // switch (iRetCode) { case 301: case 302: { // const char* pLocationStr = "Location: "; // 得到重定向后的地址 pLastPos = strstr(pHttpResponse, pLocationStr); if (pLastPos == NULL) { return 8; // 无法获取到重定向后的地址 } pLastPos += strlen(pLocationStr); // pEndPos = strstr(pLastPos, "\r\n"); // strcpy(pRefer, pHost); // memset(pHost, 0, iUrlBufSize); strncpy(pHost, pLastPos, pEndPos-pLastPos); // closesocket(scSocket); scSocket = INVALID_SOCKET; // goto tagDown; } break; case 200: case 206: { // 得到数据的大小 const char* pContentLength = "Content-Length: "; const char* pEndPos = NULL; int iHeaderLen = 0; int iDataLen = 0; bool bChunkMode = false; pLastPos = strstr(pHttpResponse, "Content-Range: "); if (pLastPos == NULL) { bUseBreakMode = false; } else { bUseBreakMode = true; } // strcpy(pTempFileUrl, localfile); strcat(pTempFileUrl, ".tmp"); // if (bUseBreakMode) { // 读取断点位置 strcpy(pBreakFileUrl, localfile); strcat(pBreakFileUrl, "_brk"); fpBreakFile = fopen(pBreakFileUrl, "rb+"); if (!fpBreakFile) { // fpBreakFile = fopen(pBreakFileUrl, "wb+"); // remove(pTempFileUrl); // 用写入的模式打开文件 fpTempFile = fopen(pTempFileUrl, "wb+"); } else { // 打开临时文件 fpTempFile = fopen(pTempFileUrl,"rb+"); if (!fpTempFile) { // 临时文件打开失败 fpTempFile = fopen(pTempFileUrl, "wb+"); if (!fpTempFile) { return 4; } // lFileOffset = 0; } else { fscanf(fpBreakFile,"%d" , &lFileOffset); fseek(fpBreakFile, lFileOffset, SEEK_SET); } } } // pLastPos = strstr(pHttpResponse, pContentLength); if (pLastPos == NULL) { // 判断是否为分块模式 const char* pTransferEncoding = "Transfer-Encoding: "; const char* pChunkStr = "chunked"; pLastPos = strstr(pHttpResponse, pContentLength); if (pLastPos == NULL) { return 8; } pLastPos += strlen(pTransferEncoding); if (strnicmp(pLastPos, pChunkStr, strlen(pChunkStr)) != 0) { return 9; } bChunkMode = true; return 12; } else { pLastPos += strlen(pContentLength); // 解析返回 pSplitStr = "\r\n"; pEndPos = strstr(pLastPos, "\r\n"); strncpy(pTempBuf, pLastPos, pEndPos-pLastPos); pTempBuf[pEndPos-pLastPos] = '\0'; iTotalDataSize = atoi(pTempBuf); } // iHeaderLen = (pHeaderEndPos - pHttpResponse); iDataLen = iRecvedTotal - iHeaderLen; if (iDataLen > 0) { if (bChunkMode) { return 12; } else { size_t nSize = 0; iRecvedFileBytes += iDataLen; lFileOffset += iDataLen; // 将数据写入文件 nSize = fwrite(pHeaderEndPos, iDataLen, 1, fpTempFile); fflush(fpTempFile); // if (bUseBreakMode) { // 写断点信息 rewind(fpBreakFile); fprintf(fpBreakFile,"%d", lFileOffset); fflush(fpBreakFile); } } } // while (true) { // 接收数据 iRecv = recv(scSocket, pHttpResponse, iRecvBufSize, 0); if (iRecv == 0) { return 10; } else if (iRecv == SOCKET_ERROR) { return 11; } else { iRecvedTotal += iRecv; // if (bChunkMode) { return 12; } else { iRecvedFileBytes += iRecv; lFileOffset += iRecv; // fwrite(pHttpResponse, iRecv, 1, fpTempFile); fflush(fpTempFile); // if (bUseBreakMode) { // 写断点信息 rewind(fpBreakFile); fprintf(fpBreakFile,"%d", lFileOffset); fflush(fpBreakFile); } // 写文件 if (iRecvedFileBytes == iTotalDataSize) { int iRet = 0; // // if (bUseBreakMode) { fclose(fpBreakFile); fpBreakFile = NULL; // remove(pBreakFileUrl); } // remove(localfile); // fclose(fpTempFile); fpTempFile = NULL; // for (i=0;;) { iRet = rename(pTempFileUrl, localfile); if (iRet != 0) { if (++i > 10) { return 13; } Sleep(1000); continue; } break; } // return 0; } } } } // } break; default: return 9; } } __finally { // 释放资源 free(pHost); free(pRefer); free(pFileUrl); free(pHttpRequest); free(pHttpResponse); free(pTempBuf); if (fpBreakFile) { fclose(fpBreakFile); } if (fpTempFile) { fclose(fpTempFile); } } return -1; }