Files
coco df489d5640 a
2026-07-03 16:05:30 +08:00

1200 lines
34 KiB
C++

//Download by http://www.NewXing.com
// HttpDownload.cpp: implementation of the HttpDownload class.
//
//------------------------------------HEADER-----------------------------
//#ifndef HTTPDOWNLOAD_H
//#define HTTPDOWNLOAD_H
#include "stdafx.h"
#include "HttpDownload.h"
#include "Constant.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
extern HHOOK hHook;
extern LRESULT __stdcall CBTHookProc(long nCode, WPARAM wParam, LPARAM lParam);
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
int threadPercent[10]={0};
HttpDownload::HttpDownload()
{
m_bSupportResume = FALSE;
m_bResume = FALSE;
m_bStop=FALSE;
m_bIsUseFile=FALSE;
m_bFileLocked =FALSE;
m_bAddSize=FALSE;
m_dwDownloadSize=0;
runningThreadCnt = 0;
nComplete = 2;//different with initial();
}
HttpDownload::~HttpDownload()
{
// fclose(globalFile); //关闭文件
// if(inforImpl.fromToImpl)
// delete[] inforImpl.fromToImpl;
}
////////////////////////////////////////////////////////
///////////////////////////////////////////////////////
//MY CODES STARTS HERE//////////////////////////////////
///////////////////////////////////////////////////////
////////////////////////////////////////////////////////
//释放内存
void HttpDownload::FreeMemory()
{
if(globalFile)
fclose(globalFile);
if(inforImpl.fromToImpl)
delete[] inforImpl.fromToImpl;
}
void HttpDownload::SetStop(bool stop)
{
m_bStop = stop;
}
//-------------------StartHttpTask()---------------------------------------------------------------------
//下载前的准备工作
//初始化变量、连接、分析返回信息、分配任务、写入inforImpl、建立文件
BOOL HttpDownload::StartHttpTask( NewTask task)
{
AfxSocketInit();
nComplete = 0;
// brushed=1;
// asked=0;
//-----------(1)------------
//从NewTask获得信息,处理一系列成员变量
m_nPort=task.port;
m_strServer=task.server;//(服务器地址)
m_strObject=task.object;//文件远端路径
m_dwThreadCnt=task.threadCnt;
m_strSavePath = task.savepath;
m_strSavePath.TrimLeft();//删除字符串前面的空格
m_strSavePath.TrimRight();//删除字符串后面的空格
if(m_strSavePath.IsEmpty() ) { //AfxMessageBox("请输入文件保存路径!");
return FALSE;
}
m_strTempSavePath = m_strSavePath;//临时文件...路径
m_strTempSavePath+= ".adam";
//----------(2)-----------
//发送请求(按照NewTask的信息)
//获得文件大小、时间等信息。
if(SendRequest(0) != SENDREQUEST_SUCCESS) {
hHook = SetWindowsHookEx(WH_CBT,(HOOKPROC)CBTHookProc,AfxGetInstanceHandle(),NULL);
// AfxMessageBox("连接失败!\n");
return FALSE;
} else {
//AfxMessageBox("连接成功!\n");
}
//-------------(3)----------
// 判断之前没有下过文件.
FILE* fp= NULL;
//配置文件不存在
if((fp = fopen(m_strTempSavePath, "r")) == NULL) {
m_bResume = FALSE; //配置文件不存在说明之前没有下过.
//AfxMessageBox("不存在"+m_strTempSavePath);
//AfxMessageBox("正在创建配置文件...");
globalFile = fopen(m_strTempSavePath,"w+b");
if(globalFile == NULL) {
//hHook = SetWindowsHookEx(WH_CBT,(HOOKPROC)CBTHookProc,AfxGetInstanceHandle(),NULL);
// AfxMessageBox("创建文件"+m_strTempSavePath+"失败");
return FALSE;
}
//创建本地文件
if(!CreateNewFile(m_strSavePath ,m_dwFileSize)) {
return false;
}
//根据文件大小和线程数分配任务写入inforImpl
GetInfofromDevision(); //
//将InforImpl中的信息写入配置文件
if(!WriteInfoToFile()) {
return false;
}
}//if()配置文件存在的情况结束
//-------------(4)----------
//配置文件存在
else {
//关闭配置文件
fclose(fp);
//从配置文件中获取下载信息,写入InforImpl
if(!GetInfofromTemp(m_strTempSavePath)) {
return false;
}
//GetInfofromtemp中调用CreateInforImpl()获取下载任务参数写入inforImpl;
//文件大小相等,并问用户是否要断点续传
if(m_dwFileSize==inforImpl.fileSize)
{
// if(asked==0)
// {
// if(AfxMessageBox("该文件曾经下过.\nURL为"+
// inforImpl.server+inforImpl.object+"\n是否断点续传?",MB_YESNO)==IDNO)
// {
// //如果用户不续传
// //删除文件
// DeleteFile(m_strSavePath+".chr");
//
//
// //创建本地文件
// if(!CreateNewFile(m_strSavePath ,m_dwFileSize)) {
// return false;
// }
//
// //根据文件大小和线程数分配任务写入inforImpl
// GetInfofromDevision(); //
//
// //将InforImpl中的信息写入配置文件
// if(!WriteInfoToFile()) {
// return false;
// }
// }
// }
// brushed=0;
}
//文件大小不相等,不续传
else {
DeleteFile(m_strSavePath+".chr");
//创建本地文件
if(!CreateNewFile(m_strSavePath ,m_dwFileSize)) {
return false;
}
//根据文件大小和线程数分配任务
GetInfofromDevision(); //
//将InforImpl中的信息写入配置文件
if(!WriteInfoToFile()) {
return false;
}
}//else
//用户选择续传问件,将inforImpl中信息写入成员变量
m_strServer=inforImpl.server;
m_strObject=inforImpl.object;
m_dwDownloadSize=inforImpl.downloadSize;
m_dwFileSize=inforImpl.fileSize;
m_dwThreadCnt=inforImpl.threadCnt;
m_bResume = TRUE;
}//if()配置文件存在的情况结束
//--------------(5)--------------
//多线程下载
CreateThread();
//--------------(6)--------------
//成功返回true
return true;
}
//-------------------------------CreateNewFile()------------------------------------------
//创建大小为size的新内容文件,加后缀.chr并使其内容为全为0
bool HttpDownload::CreateNewFile(CString fileName, DWORD size)
{
CString tempFileName = fileName + ".chr";
FILE *file;
file = fopen(tempFileName,"w+b"); //以读写方式打开空文件
if(file == NULL) {
hHook = SetWindowsHookEx(WH_CBT,(HOOKPROC)CBTHookProc,AfxGetInstanceHandle(),NULL);
// AfxMessageBox("创建文件失败!");
return false;
}
//AfxMessageBox("正在创建文件,请稍候...");
char * buffer = new char[60000];
memset(buffer,'0',60000);
DWORD writeLen = 0;
int needLen = 60000;
while(writeLen < size) {
if(writeLen + 60000 > size) {
needLen = size -writeLen;
} else
needLen = 60000;
int len = fwrite(buffer,sizeof(char),needLen,file);
if(len > 0)
writeLen += len;
}
delete[] buffer;
fclose(file);
return true;
}
//-------------------------GetInfofromDevision()---------------------------------------------------------
//下载前分配各线程任务,准备工作
void HttpDownload::GetInfofromDevision()
{
//如果不支持断点续传,则用单线程下载,令线程数为一。
if(!m_bSupportResume) {
m_dwThreadCnt=1;
hHook = SetWindowsHookEx(WH_CBT,(HOOKPROC)CBTHookProc,AfxGetInstanceHandle(),NULL);
// AfxMessageBox("服务器不支持断点续传!");
}
//在之前没下过的情况下,根据文件大小和线程数分配线程任务.
if(!m_bResume) {
inforImpl.server=m_strServer;
inforImpl.object=m_strObject;
inforImpl.savePath=m_strSavePath; //保存路径
inforImpl.fileSize=m_dwFileSize; //文件大小
inforImpl.threadCnt=m_dwThreadCnt; //线程数
inforImpl.downloadSize=0; //已经下载文件大小
DWORD perCnt = inforImpl.fileSize / inforImpl.threadCnt;
inforImpl.fromToImpl = new FromToImpl[m_dwThreadCnt];
//依次写入各线程下载的始末地址
int i = 0;
for(i = 0 ;i <inforImpl.threadCnt-1 ; i++) {
inforImpl.fromToImpl[i].from = perCnt * i;
inforImpl.fromToImpl[i].to = perCnt*(i+1);
}
inforImpl.fromToImpl[i].from = perCnt*(i);
inforImpl.fromToImpl[i].to =inforImpl.fileSize;
}
}
//-------------------------GetInfofromtemp()---------------------------------------------------------
//从配置文件中获取下载任务参数
bool HttpDownload::GetInfofromTemp(CString fileName)
{
char *buffer = new char[5000];
while(m_bFileLocked)
Sleep(50);
m_bFileLocked = true;
globalFile=fopen(fileName,"r+b");
if(globalFile==NULL) {
// AfxMessageBox("打开配置文件失败!");
return false;
}
fseek(globalFile,0,2);
int fileLen = ftell(globalFile);
fseek(globalFile,0,0);
int readLen = fread(buffer,sizeof(char),fileLen,globalFile);
buffer[readLen] = 0;
CString str(buffer);
delete[] buffer;
if(str.IsEmpty()) {
m_bResume=false;
m_bFileLocked = false;
// AfxMessageBox("配置文件为空!\n重新下载");
//根据文件大小和线程数分配任务
GetInfofromDevision(); //
//将InforImpl中的信息写入配置文件
if(!WriteInfoToFile()) {
return false;
}
return true;
}
m_bFileLocked = false;
CreateInforImpl(str);//...获得参数,写入InforImpl
return true;
}
//--------------------------CreateInforImpl()---------------------------------------------------------
//...获得参数,写入InforImpl
void HttpDownload::CreateInforImpl(CString str)
{
//获得断点续传的参数
int index;
CString temp;
CString server;
CString object;
DWORD fileSize;
DWORD downloadSize;
int threadCnt;
index = str.Find("\r\n");
server=str.Left(index); //获得服务器地址
str = str.Mid(index+2,str.GetLength()-index);
index = str.Find("\r\n");
object=str.Left(index); //获得文件远端路径
str = str.Mid(index+2,str.GetLength()-index);
index = str.Find("\r\n");
m_strSavePath =str.Left(index); //获取文件的保存地址
str = str.Mid(index+2,str.GetLength()-index);
index = str.Find("\r\n");
fileSize =(DWORD)_ttoi((LPCTSTR)str.Left(index)); //获取文件大小
str = str.Mid(index+2,str.GetLength() -index);
index = str.Find("\r\n");
threadCnt =(DWORD)_ttoi((LPCTSTR)str.Left(index)); //获取线程数目
str = str.Mid(index+2,str.GetLength() - index);
index = str.Find("\r\n");
downloadSize=(DWORD)_ttoi((LPCTSTR)str.Left(index)); //获取已经下载文件的大小
str = str.Mid(index+2,str.GetLength() - index);
//赋值给inforImpl结构
inforImpl.server =server;
inforImpl.object=object;
inforImpl.fromToImpl = new FromToImpl[m_dwThreadCnt];
inforImpl.savePath = m_strSavePath;
inforImpl.fileSize = fileSize;
inforImpl.threadCnt = threadCnt;
inforImpl.downloadSize = downloadSize;
CString from ,to;
for(int i =0 ;i<inforImpl.threadCnt ; i++) {
index = str.Find("\r\n");
temp = str.Left(index); // 获取from - to 值
str = str.Mid(index +2 ,str.GetLength() - index);
index = temp.Find("-");
from = temp.Left(index);
to = temp.Mid(index+1,temp.GetLength() - index);
inforImpl.fromToImpl[i].from =(DWORD)_ttoi((LPCTSTR)from);
inforImpl.fromToImpl[i].to =(DWORD)_ttoi((LPCTSTR)to);
}
//===============debug==============================
//CWnd OutPut;
//CString stri;
//stri.Format("readLen=%d",readLen);
//OutPut.MessageBox(stri);
//===============debug end===========================
}
//---------------------------SendRequest()-------------------------------------------------------------
//发送请求,并分析响应消息
UINT HttpDownload::SendRequest(BOOL bHead)//...bHead=1,HEAD;bHead=0,GET .
{
CString strVerb;
if( bHead )
strVerb = _T("HEAD ");
else
strVerb = _T("GET ");
CString strSend,strHeader,strRange;
int iStatus = 0,nRet;
char szReadBuf[1025];
DWORD dwContentLength,dwStatusCode;
while (TRUE)
{
if(m_pSocket.m_hSocket != NULL)
m_pSocket.Close();
//建立Socket
m_pSocket.Create();
//连接
m_pSocket.Connect(m_strServer, m_nPort);
//建立发送信息串strSend
strSend = strVerb + m_strObject + " HTTP/1.1\r\n";
strSend += "Host: " + m_strServer + "\r\n";
strSend += "Accept: */*\r\n";
strSend += "Pragma: no-cache\r\n";
strSend += "Cache-Control: no-cache\r\n";
if( !m_strReferer.IsEmpty() )
strSend += "Referer: " + m_strReferer + "\r\n";
strSend += "Connection: close\r\n";
strRange = "Range: bytes=100-\r\n";
strSend += strRange;
//必须要加一个空行,否则Http服务器将不会应答
strSend += "\r\n";
//=====================debug=======================
//AfxMessageBox("---strsend---\n"+strSend);
//=====================debug end===================
int ret = m_pSocket.Send(strSend.GetBuffer(0), strSend.GetLength());
strSend.ReleaseBuffer();
strHeader.Empty();
ZeroMemory(szReadBuf,1025);
ret = m_pSocket.Receive(szReadBuf, 1025);
strHeader += szReadBuf;
//====================debug=========================
//AfxMessageBox("receive strHeader:\n"+strHeader);
//=================debug end========================
nRet = GetInfo(strHeader,dwContentLength,
dwStatusCode,m_TimeLastModified);//直接把时间写入http类
switch ( nRet ) {
case HTTP_FAIL:
return SENDREQUEST_FAIL;
break;
case HTTP_ERROR:
return SENDREQUEST_ERROR;
break;
case HTTP_REDIRECT:
continue;
break;
case HTTP_OK:
//m_dwDownloadSize = dwContentLength + 100;
// 判断一下服务器是否支持断点续传
if( strRange.IsEmpty() )
m_dwFileSize = dwContentLength + 100; // 整个文件的长度
else {
if ( dwStatusCode == 206 ) { //支持断点续传
m_bSupportResume = TRUE;
m_dwFileSize = dwContentLength + 100;
} else { //不支持断点续传
m_bSupportResume = FALSE;
m_dwFileSize = dwContentLength + 100;
}
}
return SENDREQUEST_SUCCESS;//......成功!!!!
break;
default:
return SENDREQUEST_FAIL;
break;
}
}
m_pSocket.Close();
return SENDREQUEST_SUCCESS;
}
//---------------------------GetInfo()----------------------------------------------------------------
//分析响应消息,获得返回码,时间,文件长度等信息
UINT HttpDownload::GetInfo(LPCTSTR lpszHeader, DWORD &dwContentLength,
DWORD &dwStatusCode, CTime &TimeLastModified)
{
dwContentLength = 0;
dwStatusCode = 0;
TimeLastModified= CTime::GetCurrentTime();
CString strHeader = lpszHeader;
strHeader.MakeLower();//...将strHeader转为小写.
//拆分出HTTP应答的头信息的第一行
int nPos = strHeader.Find("\r\n");
if (nPos == -1)
return HTTP_FAIL;
CString strFirstLine = strHeader.Left(nPos);
// 获得返回码: Status Code
strFirstLine.TrimLeft();
strFirstLine.TrimRight();
nPos = strFirstLine.Find(' ');
if( nPos == -1 )
return HTTP_FAIL;
strFirstLine = strFirstLine.Mid(nPos+1);
nPos = strFirstLine.Find(' ');
if( nPos == -1 )
return HTTP_FAIL;
strFirstLine = strFirstLine.Left(nPos);
dwStatusCode = (DWORD)_ttoi((LPCTSTR)strFirstLine);//...转换为整型
// 检查返回码
if( dwStatusCode >= 300 && dwStatusCode < 400 ) { //检测服务器的应答是否为重定向
nPos = strHeader.Find("location:");
if (nPos == -1)
return HTTP_FAIL;
CString strRedirectFileName = strHeader.Mid(nPos + strlen("location:"));
nPos = strRedirectFileName.Find("\r\n");
if (nPos == -1)
return HTTP_FAIL;
strRedirectFileName = strRedirectFileName.Left(nPos);
strRedirectFileName.TrimLeft();
strRedirectFileName.TrimRight();//为重定向文件路径
// 设置Referer
m_strReferer = m_strDownloadUrl;//..???????这里的m_strDownloadUrl初始化了吗?
// 判断是否重定向到其他的服务器
nPos = strRedirectFileName.Find("http://");
// 重定向到其他服务器
if( nPos != -1 ) {
m_strDownloadUrl = strRedirectFileName;
// 检验要下载的URL是否有效
if ( !ParseURL(m_strDownloadUrl))
return HTTP_FAIL;
return HTTP_REDIRECT;
}
// 重定向到本服务器的其他地方
strRedirectFileName.Replace("\\","/");
//相对于根目录
if( strRedirectFileName[0] == '/' ) {
m_strObject = strRedirectFileName;
return HTTP_REDIRECT;
}
// 相对当前目录
int nParentDirCount = 0;
nPos = strRedirectFileName.Find("../");
while (nPos != -1) {
strRedirectFileName = strRedirectFileName.Mid(nPos+3);
nParentDirCount++;
nPos = strRedirectFileName.Find("../");
}
for (int i=0; i<=nParentDirCount; i++) {
nPos = m_strDownloadUrl.ReverseFind('/');
if (nPos != -1)
m_strDownloadUrl = m_strDownloadUrl.Left(nPos);
}
m_strDownloadUrl = m_strDownloadUrl+"/"+strRedirectFileName;
if ( !ParseURL(m_strDownloadUrl))
return HTTP_FAIL;
return HTTP_REDIRECT;
}
// 服务器错误,可以重试
if( dwStatusCode >= 500 )
return HTTP_ERROR;
// 客户端错误,重试无用
if( dwStatusCode >=400 && dwStatusCode <500 )
return HTTP_FAIL;
// 获取ContentLength
nPos = strHeader.Find("content-length:");
if (nPos == -1)
return HTTP_FAIL;
CString strDownFileLen = strHeader.Mid(nPos + strlen("content-length:"));
nPos = strDownFileLen.Find("\r\n");
if (nPos == -1)
return HTTP_FAIL;
strDownFileLen = strDownFileLen.Left(nPos);
strDownFileLen.TrimLeft();
strDownFileLen.TrimRight();
// Content-Length:
dwContentLength = (DWORD) _ttoi( (LPCTSTR)strDownFileLen );//转换为整型
// 获取Last-Modified:
nPos = strHeader.Find("last-modified:");
if (nPos != -1) {
CString strTime = strHeader.Mid(nPos + strlen("last-modified:"));
nPos = strTime.Find("\r\n");
if (nPos != -1) {
strTime = strTime.Left(nPos);
strTime.TrimLeft();
strTime.TrimRight();
TimeLastModified = GetTime(strTime);
}
}
return HTTP_OK;
}
//------------------------------ParseURL()-----------------------------------------------------------
//地址解析
BOOL HttpDownload::ParseURL(CString str)
{
str.TrimLeft();
if(str.IsEmpty())
return FALSE;
CString strURL = str;
// 清除数据
m_strServer = _T("");
m_strObject = _T("");
m_nPort = 0;
int nPos = strURL.Find("://");
if( nPos == -1 )
return FALSE;
// 进一步验证是否为http://
CString strTemp = strURL.Left( nPos+lstrlen("://") );
strTemp.MakeLower();
if( strTemp.Compare("http://") != 0 )
return FALSE;
strURL = strURL.Mid( strTemp.GetLength() );
nPos = strURL.Find('/');
if ( nPos == -1 )
return FALSE;
m_strObject = strURL.Mid(nPos);
strTemp = strURL.Left(nPos);
// 查找是否有端口号
nPos = strTemp.Find(":");
if( nPos == -1 ) {
m_strServer = strTemp;
m_nPort = DEFAULT_HTTP_PORT;
} else {
m_strServer = strTemp.Left( nPos );
strTemp = strTemp.Mid( nPos+1 );
m_nPort = (USHORT)_ttoi((LPCTSTR)strTemp);//...字符串转化为短整型如果是Unicode,
//编译时编译为_atoi如果是ANSI,编译为_wtoi
}
return TRUE;
}
//--------------------------GetTime-----------------------------------------------------------------
//获得CTime时间
CTime HttpDownload::GetTime(LPCTSTR lpszTime)
{
int nDay,nMonth,nYear,nHour,nMinute,nSecond;
CString strTime = lpszTime;
int nPos = strTime.Find(',');
if (nPos != -1) {
strTime = strTime.Mid(nPos+1);
strTime.TrimLeft();
CString strDay,strMonth,strYear,strHour,strMinute,strSecond;
CString strAllMonth = "jan,feb,mar,apr,may,jan,jul,aug,sep,oct,nov,dec";
strDay = strTime.Left(2);
nDay = atoi(strDay);
strMonth = strTime.Mid(3,3);
strMonth.MakeLower();
nPos = strAllMonth.Find(strMonth);
if (nPos != -1) {
strMonth.Format("%d",((nPos/4)+1));
nMonth = atoi(strMonth);
} else
nMonth = 1;
strTime = strTime.Mid(6);
strTime.TrimLeft();
nPos = strTime.FindOneOf(" \t");
if (nPos != -1) {
strYear = strTime.Left(nPos);
nYear = atoi(strYear);
} else
nYear = 2000;
strTime = strTime.Mid(nPos+1);
strHour = strTime.Left(2);
nHour = atoi(strHour);
strMinute = strTime.Mid(3,2);
nMinute = atoi(strMinute);
strSecond = strTime.Mid(6,2);
nSecond = atoi(strSecond);
}
CTime time(nYear,nMonth,nDay,nHour,nMinute,nSecond);
return time;
}
//--------------------------WriteInfoToFile()---------------------------------------------------------
//将下载任务的信息按固定格式写入配置文件
bool HttpDownload::WriteInfoToFile()
{
CString writeStr;
CString fileSizeStr;
CString threadCntStr;
CString downloadSizeStr;
CString from;
CString to;
fileSizeStr.Format("%d",inforImpl.fileSize);
threadCntStr.Format("%d",inforImpl.threadCnt);
downloadSizeStr.Format("%d",m_dwDownloadSize);
//写入配置文件的内容
//文件保存路径
//文件大小
//线程数
//已下载大小
//各线程的始末位置 “*****-*****”
writeStr =m_strServer+"\r\n"+m_strObject+"\r\n"+m_strSavePath+"\r\n"+fileSizeStr+"\r\n"+threadCntStr+"\r\n"+downloadSizeStr+"\r\n";
for(int i = 0; i< inforImpl.threadCnt ; i++) {
from.Format("%d",inforImpl.fromToImpl[i].from);
to.Format("%d",inforImpl.fromToImpl[i].to);
writeStr +=from +"-"+to+"\r\n";
}
while(m_bFileLocked)
Sleep(10);
m_bFileLocked = true;
if(globalFile == NULL) {
m_bFileLocked = false;
return false;
}
try {
fseek(globalFile,0,0);
fwrite(writeStr,sizeof(char),writeStr.GetLength(),globalFile);
m_bFileLocked = false;
return true;
} catch(...) {
m_bFileLocked = false;
return false;
// AfxMessageBox("将信息写入配置文件出错!");
}
}
//--------------------------------CreateThread()--------------------------------------------------------
//多线程下载部分
void HttpDownload::CreateThread()
{
if(!m_bStop) {
CString s_ThreadCnt;
//s_ThreadCnt.Format("将创建 %d 个线程!\n",m_dwThreadCnt);
//AfxMessageBox(s_ThreadCnt);
//DWORD dwThread;
m_index = 0;
CWinThread* Thread[10];
for(int i = 0; i<m_dwThreadCnt; i++) {
Thread[i]=AfxBeginThread(threadFun,(LPVOID)this);//启动线程
runningThreadCnt++;
}
}
}
//-------------------------------------Download()-------------------------------------------------------
//每个线程的下载函数
bool HttpDownload::Download(int index)
{
AfxSocketInit();
nComplete = 0;
CString s_index;
s_index.Format("线程%d",index);
//AfxMessageBox(s_index+"启动");
if(inforImpl.fromToImpl[index].from==inforImpl.fromToImpl[index].to) {
threadPercent[index]=100;
runningThreadCnt--;
return true;
}
CSocket pSocket;
pSocket.Create();
if(!m_bStop&&inforImpl.fromToImpl[index].from < inforImpl.fromToImpl[index].to) {
//发送请求
int firstLen;
pSocket.Connect(m_strServer, m_nPort);
CString strSend, strRange;
strSend = "GET " + m_strObject + " HTTP/1.1\r\n";
strSend += "Host: " + m_strServer + "\r\n";
strSend += "Accept: */*\r\n";
strSend += "Pragma: no-cache\r\n";
strSend += "Cache-Control: no-cache\r\n";
if( !m_strReferer.IsEmpty() )
strSend += "Referer: " + m_strReferer + "\r\n";
strSend += "Connection: close\r\n";
strRange.Format("Range: bytes=%d-%d\r\n",inforImpl.fromToImpl[index].from, inforImpl.fromToImpl[index].to);
if(m_bSupportResume)
strSend += strRange;
//必须要加一个空行,否则服务器将不应答
strSend += "\r\n";
int re =pSocket.Send(strSend.GetBuffer(0), strSend.GetLength());//
strSend.ReleaseBuffer();//??GetBuffer的用法
//AfxMessageBox(strSend);
DWORD lpArgument;
if(!pSocket.AsyncSelect(0) && !pSocket.IOCtl(FIONBIO, &lpArgument)) {
// AfxMessageBox("Error!");
runningThreadCnt--;
return false; //...
//The lpArgument parameter points at a DWORD, which is nonzero if nonblocking mode
//is to be enabled and zero if it is to be disabled.
}
char szReadBuf[1024];
ZeroMemory(szReadBuf,1024);
DWORD ret = pSocket.Receive(szReadBuf, 1024);//...ret=the number of bytes received
DWORD headLen= GetHeadLength(szReadBuf);
//szReadBuf[ret]=0;
//取响应消息的长度,这部分不写入文件
if(ret-headLen<inforImpl.fromToImpl[index].to-inforImpl.fromToImpl[index].from) {
firstLen=ret-headLen;//第一次下载的文件的长度
} else {
firstLen=inforImpl.fromToImpl[index].to-inforImpl.fromToImpl[index].from;
}
while(m_bAddSize) {
Sleep(50);
}
m_bAddSize=TRUE;
m_dwDownloadSize+=firstLen;
m_bAddSize=FALSE;
inforImpl.fromToImpl[index].from+=firstLen;
WriteToFile(m_strSavePath,inforImpl.fromToImpl[index].from-firstLen,
szReadBuf+headLen,firstLen);//第一次下载的写入内容文件
WriteInfoToFile();//...将下载信息写入adam文件
}//if
while(!m_bStop&&inforImpl.fromToImpl[index].from < inforImpl.fromToImpl[index].to) {
DWORD pos=inforImpl.fromToImpl[index].from;
DWORD len=PER_GETLEN;
if(inforImpl.fromToImpl[index].to-inforImpl.fromToImpl[index].from>PER_GETLEN) {
len=PER_GETLEN;
} else {
len=inforImpl.fromToImpl[index].to-inforImpl.fromToImpl[index].from;
}
char *buffer = new char[len];
DWORD cnt =0 ;
while(!m_bStop && cnt < len) { //下载没有中止并且没存满,先将len存到缓冲区
int recLen =pSocket.Receive(buffer+cnt,len-cnt,0); //接收数据
if(recLen > 0) {
cnt += recLen;
while(m_bAddSize) {
Sleep(50);
}
m_bAddSize=TRUE;
m_dwDownloadSize+= recLen;
m_bAddSize=FALSE;
inforImpl.fromToImpl[index].from += recLen;
threadPercent[index]=(int)( ( (double)inforImpl.fromToImpl[index].from-
m_dwFileSize/m_dwThreadCnt*index )*100/( inforImpl.fromToImpl[index].to-
m_dwFileSize/m_dwThreadCnt*index ) );
} else {
if(recLen < 0) {
//AfxMessageBox("下载有误,请检查连接");
runningThreadCnt--;
break;
} else {
continue;
}
}//else
}//while
if(cnt < len || cnt == 0) {
// AfxMessageBox("下载文件失败!");
Initial(1);
delete[] buffer;
runningThreadCnt--;
return false;
} else {
// "下载了一部分数据"
//...将数据写入文件
WriteToFile(m_strSavePath,pos,buffer,len);
WriteInfoToFile();//...将下载信息写入文件
if(m_dwDownloadSize==m_dwFileSize) {//...下载完毕,删除配置文件,重命名内容文件
//this->DoOnComplete();
WriteInfoToFile();
CString profile =m_strTempSavePath;
fclose(globalFile);
CString oldName =m_strSavePath+ ".chr";
rename(oldName,m_strSavePath);
DeleteFile(profile);
fclose(globalFile); //关闭文件
if(inforImpl.fromToImpl)
delete[] inforImpl.fromToImpl;
// AfxMessageBox("下载完成\n\n已保存到");
Initial(2);
}
}
delete[] buffer;
}
runningThreadCnt --;
return true;
}
////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////
/*
bool HttpDownload::realDownload(DWORD pos ,DWORD len,int index,CSocket sock) //下载数据
{
char *buffer = new char[len];
DWORD cnt =0 ;
while(!m_bStop && cnt < len){ //下载没有中止并且没存满,先将len存到缓冲区
int recLen =sock.Receive(buffer+cnt,len-cnt,0); //接收数据
if(recLen > 0){
cnt += recLen;
while(m_bAddSize){
Sleep(50);
}
m_bAddSize=TRUE;
m_dwDownloadSize+= recLen;
m_bAddSize=FALSE;
inforImpl.fromToImpl[index].from += recLen;
}
else{
if(recLen < 0){
AfxMessageBox("下载有误");
break;
}
else{
continue;
}
}//else
}//while
if(cnt < len || cnt == 0){
AfxMessageBox("下载文件失败!");
delete[] buffer;
return false;
}
else{
// "下载了一部分数据"
//...将数据写入文件
WriteToFile(m_strSavePath,pos,buffer,len);
WriteInfoToFile();//...将下载信息写入文件
if(m_dwDownloadSize==m_dwFileSize)//...下载完毕,删除配置文件,重命名内容文件
{
//this->DoOnComplete();
WriteInfoToFile();
CString profile =m_strTempSavePath;
fclose(globalFile);
CString oldName =m_strSavePath+ ".chr";
rename(oldName,m_strSavePath);
DeleteFile(profile);
AfxMessageBox("下载完成!");
}
}
delete[] buffer;
return true;
}//realDownload
*/
///////////////////////////////////////////////////////////////////////
//-----------------------------------GetHeadLength()-------------------------------------------
int HttpDownload::GetHeadLength(char *lpData)
{
//...得到Head串的长度,遇到空行停止
int ndx = 0;
CString str;
while(1) {
str.Empty();
str = GetLine(lpData, ndx);
if(str.IsEmpty())
break;
}
return (ndx);
}
CString HttpDownload::GetLine(char *lpData, int& ndx)
{
//...从lpData串中取出一行,ndx为该行最后一个字符下标。
BOOL bLine = FALSE;
CString str;
while ( bLine == FALSE && ndx < 1025 ) {
char ch = (char)(lpData[ndx]);
switch( ch ) {
case '\r': // ignore
break;
case '\n': // end-of-line
bLine = TRUE;
break;
default: // other....
str += ch;
break;
}
++ndx;
}
return str;
}
void HttpDownload::Initial(int n)
{
m_bSupportResume = FALSE;
m_bResume = FALSE;
m_bStop=FALSE;
m_bIsUseFile=FALSE;
m_bFileLocked =FALSE;
m_bAddSize=FALSE;
m_dwDownloadSize=0;
runningThreadCnt = 0;
nComplete = n;//different with HttpDownload();
}
//--------------------------------WriteToFile()------------------------------------------------------------------
//将buffer中的数据写入filePath的pos位置
bool HttpDownload::WriteToFile(CString filePath,DWORD pos ,char *buffer , int len)
{
CString tempFileName = filePath + ".chr";
while(m_bIsUseFile)
Sleep(50);
m_bIsUseFile = true;
FILE *file ;
file = fopen(tempFileName,"r+b");
if(file == NULL) {
CString str=m_strSavePath + ".adam";
fclose(globalFile);
//删掉配置文件
DeleteFile(str);
// AfxMessageBox("写入内容文件失败!");
m_bIsUseFile = false;
return false;
}
fseek(file,pos,0);
fwrite(buffer,sizeof(char),len,file);
fclose(file);
m_bIsUseFile = false;
return true;
}
//=============================threadFun()============================================================
UINT threadFun(LPVOID lparam)
{
HttpDownload* pThis = (HttpDownload*)lparam;
int index= pThis->m_index;
//pThis->m_index++;
InterlockedIncrement(&pThis->m_index);
//CString s_index;
//s_index.Format("%d",index);
//AfxMessageBox("调用threadFun"+s_index);
int ret=pThis->Download(index);
return true;
}