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;
}
http下载
最新推荐文章于 2024-11-07 14:48:32 发布