`
winzenghua
  • 浏览: 1329551 次
  • 性别: Icon_minigender_2
  • 来自: 广州
文章分类
社区版块
存档分类
最新评论

vc++实现http下载的通用类

阅读更多

// DownloadHttp.cpp: implementation of the CDownloadHttp class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "downtest.h"
#include "DownloadHttp.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

void DownloadNotify ( int nIndex, UINT nNotityType, LPVOID lpNotifyData, LPVOID pDownloadMTR );

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CDownloadHttp::CDownloadHttp()
{

}

CDownloadHttp::~CDownloadHttp()
{

}

BOOL CDownloadHttp::DownloadOnce()
{
// 不需要下载了
int nWillDownloadSize = Get_WillDownloadSize();// 本次应该下载的字节数
int nDownloadedSize = Get_DownloadedSize ();// 已下载字节数
if ( nWillDownloadSize > 0 && nDownloadedSize >= nWillDownloadSize )
return DownloadEnd(TRUE);

if ( !CDownloadPub::DownloadOnce () )
return DownloadEnd(FALSE);

char szTailData[NET_BUFFER_SIZE] = {0};
int nTailSize = sizeof(szTailData);
if ( !RequestHttpData ( TRUE, szTailData, &nTailSize ) )
return DownloadEnd(FALSE);
// 从HTTP服务器中读取数据,并保存到文件中
return DownloadEnd ( RecvDataAndSaveToFile(m_SocketClient,szTailData, nTailSize) );

}

BOOL CDownloadHttp::RequestHttpData(BOOL bGet, char *szTailData/*=NULL*/, int *pnTailSize/*=NULL*/ )
{
int nTailSizeTemp = 0;
BOOL bRetryRequest = TRUE;
while ( bRetryRequest )
{
CString csReq = GetRequestStr ( bGet );
CString csResponse;
nTailSizeTemp = pnTailSize?(*pnTailSize):0;
if ( !SendRequest ( csReq, csResponse, szTailData, &nTailSizeTemp ) )
return FALSE;

CString csReferer_Old = m_csReferer;
CString csDownloadUrl_Old = m_csDownloadUrl;
CString csServer_Old = m_csServer;
CString csObject_Old = m_csObject;
USHORT nPort_Old = m_nPort;
CString csProtocolType_Old = m_csProtocolType;
if ( !ParseResponseString ( csResponse, bRetryRequest ) )
{
if ( !m_csCookieFlag.IsEmpty () )
{
m_csCookieFlag.Empty();
return FALSE;
}
m_csReferer = csReferer_Old;
m_csDownloadUrl = csDownloadUrl_Old;
m_csServer = csServer_Old;
m_csObject = csObject_Old;
m_nPort = nPort_Old;
m_csProtocolType = csProtocolType_Old;
m_csCookieFlag = "Flag=UUIISPoweredByUUSoft";
bRetryRequest = TRUE;
}
}
if ( pnTailSize )
*pnTailSize = nTailSizeTemp;

return TRUE;
}

//
// 获取远程站点信息,如:是否支持断点续传、要下载的文件大小和创建时间等
//
BOOL CDownloadHttp::GetRemoteSiteInfo_Pro()
{
BOOL bRet = FALSE;
if ( !CDownloadPub::GetRemoteSiteInfo_Pro() )
goto finished;

if ( !RequestHttpData ( TRUE ) )
goto finished;

bRet = TRUE;

finished:
return bRet;
}

CString CDownloadHttp::GetRequestStr(BOOL bGet)
{
CString strVerb;
if( bGet )
strVerb = _T("GET ");
else
strVerb = _T("HEAD ");

CString csReq, strAuth, strRange;
csReq = strVerb + m_csObject + " HTTP/1.1\r\n";

if ( !m_csUsername.IsEmpty () )
{
strAuth = _T("");
Base64Encode ( m_csUsername + ":" + m_csPassword, strAuth );
csReq += "Authorization: Basic " + strAuth + "\r\n";
}

CString csPort;
if ( m_nPort != DEFAULT_HTTP_PORT )
csPort.Format ( ":%d", m_nPort );
csReq += "Host: " + m_csServer + csPort + "\r\n";
csReq += "Accept: */*\r\n";
csReq += "Pragma: no-cache\r\n";
csReq += "Cache-Control: no-cache\r\n";
csReq += "User-Agent: "+m_csUserAgent+"\r\n";
if( m_csReferer.IsEmpty() )
{
m_csReferer = GetRefererFromURL ();
}
csReq += "Referer: "+m_csReferer+"\r\n";
csReq += "Connection: close\r\n";
if ( !m_csCookieFlag.IsEmpty() )
{
csReq += "Cookie: " + m_csCookieFlag + "\r\n";
}

// 指定要下载的文件范围
CString csEndPos;
int nWillDownloadStartPos = Get_WillDownloadStartPos ();// 开始位置
int nWillDownloadSize = Get_WillDownloadSize();// 本次应该下载的字节数
int nDownloadedSize = Get_DownloadedSize ();// 已下载字节数
if ( nWillDownloadSize > 0 )
csEndPos.Format ( "%d", nWillDownloadStartPos+nWillDownloadSize-1 );
ASSERT ( nWillDownloadSize < 0 || nDownloadedSize < nWillDownloadSize );
strRange.Format ( _T("Range: bytes=%d-%s\r\n"), nWillDownloadStartPos+nDownloadedSize, csEndPos );

csReq += strRange;
csReq += "\r\n";

return csReq;
}

//
// 向服务器提交请求,并得到返回字符串
//
BOOL CDownloadHttp::SendRequest(LPCTSTR lpszReq, CString &csResponse, char *szTailData/*=NULL*/, int *pnTailSize/*=NULL*/ )
{
m_SocketClient.Disconnect ();
if ( !Connect () ) return FALSE;
if ( !m_SocketClient.SendString ( lpszReq ) )
{
return FALSE;
}

for ( int i=0; ; i++ )
{
char szRecvBuf[NET_BUFFER_SIZE] = {0};
int nReadSize = m_SocketClient.Receive ( szRecvBuf, sizeof(szRecvBuf) );
if ( nReadSize <= 0 )
{
Log ( L_WARNING, "(%d) Receive response data failed", m_nIndex );
return FALSE;
}
csResponse += szRecvBuf;
char *p = strstr ( szRecvBuf, "\r\n\r\n" );
if ( p )
{
if ( szTailData && pnTailSize && *pnTailSize > 0 )
{
p += 4;
int nOtioseSize = nReadSize - int( p - szRecvBuf );
*pnTailSize = MIN ( nOtioseSize, *pnTailSize );
memcpy ( szTailData, p, *pnTailSize );
}
#ifdef _DEBUG
int nPos = csResponse.Find ( "\r\n\r\n", 0 );
CString csDump;
if ( nPos >= 0 ) csDump = csResponse.Left ( nPos );
else csDump = csResponse;
Log ( L_NORMAL, "(%d) HTTP server response : \r\n<<<++++++++++++++++++++++++\r\n%s\r\n<<<++++++++++++++++++++++++",
m_nIndex, csDump );
#endif
break;
}
}

return TRUE;
}

DWORD CDownloadHttp::GetResponseCode(CString csLineText)
{
csLineText.MakeLower ();
ASSERT ( csLineText.Find ( "http/", 0 ) >= 0 );
int nPos = csLineText.Find ( " ", 0 );
if ( nPos < 0 ) return 0;
CString csCode = csLineText.Mid ( nPos + 1 );
csCode.TrimLeft(); csCode.TrimRight();
nPos = csCode.Find ( " ", 0 );
if ( nPos < 0 ) nPos = csCode.GetLength() - 1;
csCode = csCode.Left ( nPos );

return (DWORD)atoi(csCode);
}

BOOL CDownloadHttp::ParseResponseString ( CString csResponseString, OUT BOOL &bRetryRequest )
{
bRetryRequest = FALSE;
// 获取返回代码
CString csOneLine = GetOneLine ( csResponseString );
DWORD dwResponseCode = GetResponseCode ( csOneLine );
if ( dwResponseCode < 1 )
{
Log ( L_WARNING, "(%d) Received error response code : %s", m_nIndex, csOneLine );
return FALSE;
}

int nPos = 0;
// 请求文件被重定向
if( dwResponseCode >= 300 && dwResponseCode < 400 )
{
bRetryRequest = TRUE;
// 得到请求文件新的URL
CString csRedirectFileName = FindAfterFlagString ( "location:", csResponseString );

// 设置 Referer
m_csReferer = GetRefererFromURL ();

// 重定向到其他的服务器
nPos = csRedirectFileName.Find("://");
if ( nPos >= 0 )
{
m_csDownloadUrl = csRedirectFileName;
// 检验要下载的URL是否有效
if ( !ParseURL ( m_csDownloadUrl, m_csServer, m_csObject, m_nPort, m_csProtocolType ) )
{
Log ( L_WARNING, "(%d) Redirect media path [%s] invalid", m_nIndex, m_csDownloadUrl );
return FALSE;
}
return TRUE;
}

// 重定向到本服务器的其他地方
csRedirectFileName.Replace ( "\\", "/" );
// 重定向于根目录
if( csRedirectFileName[0] == '/' )
{
m_csObject = csRedirectFileName;
DownloadNotify ( -1, NOTIFY_TYPE_GOT_REMOTE_FILENAME, (LPVOID)(LPCTSTR)(GetDownloadObjectFileName()), m_pDownloadMTR );
return TRUE;
}

// 定向于相对当前目录
int nParentDirCount = 0;
nPos = csRedirectFileName.Find ( "../" );
while ( nPos >= 0 )
{
csRedirectFileName = csRedirectFileName.Mid(nPos+3);
nParentDirCount++;
nPos = csRedirectFileName.Find("../");
}
for (int i=0; i<=nParentDirCount; i++)
{
nPos = m_csDownloadUrl.ReverseFind('/');
if (nPos != -1)
m_csDownloadUrl = m_csDownloadUrl.Left(nPos);
}
if ( csRedirectFileName.Find ( "./", 0 ) == 0 )
csRedirectFileName.Delete ( 0, 2 );
m_csDownloadUrl = m_csDownloadUrl+"/"+csRedirectFileName;

return ParseURL ( m_csDownloadUrl, m_csServer, m_csObject, m_nPort, m_csProtocolType );
}
// 请求被成功接收、理解和接受
else if( dwResponseCode >= 200 && dwResponseCode < 300 )
{
if ( m_nIndex == -1 )// 主线程才需要获取文件大小的信息
{
// 获取 Content-Length
CString csDownFileLen = FindAfterFlagString ( "content-length:", csResponseString );
m_nFileTotalSize = (int) _ttoi( (LPCTSTR)csDownFileLen );
DownloadNotify ( -1, NOTIFY_TYPE_GOT_REMOTE_FILESIZE, (LPVOID)m_nFileTotalSize, m_pDownloadMTR );
int nWillDownloadStartPos = Get_WillDownloadStartPos ();// 开始位置
int nWillDownloadSize = Get_WillDownloadSize();// 本次应该下载的字节数
int nDownloadedSize = Get_DownloadedSize ();// 已下载字节数
if ( m_nFileTotalSize > 0 && nWillDownloadSize-nDownloadedSize > m_nFileTotalSize )
Set_WillDownloadSize ( m_nFileTotalSize-nDownloadedSize );
}

// 获取服务器文件的最后修改时间
CString csModifiedTime = FindAfterFlagString ( "last-modified:", csResponseString );
if ( !csModifiedTime.IsEmpty() )
{
m_TimeLastModified = ConvertHttpTimeString(csModifiedTime);
}

if ( dwResponseCode == 206 )// 支持断点续传
{
m_bSupportResume = TRUE;
}
else// 不支持断点续传
{
m_bSupportResume = FALSE;
}
return TRUE;
}

//Log ( L_WARNING, "(%d) Receive invalid code : %d", m_nIndex, dwResponseCode );
return FALSE;
}

CString CDownloadHttp::FindAfterFlagString(LPCTSTR lpszFoundStr, CString csOrg)
{
ASSERT ( lpszFoundStr && strlen(lpszFoundStr) > 0 );
CString csReturing, csFoundStr = GET_SAFE_STRING(lpszFoundStr);
csFoundStr.MakeLower ();
CString csOrgLower = csOrg;
csOrgLower.MakeLower ();
int nPos = csOrgLower.Find ( csFoundStr );
if ( nPos < 0 ) return "";
csReturing = csOrg.Mid ( nPos + csFoundStr.GetLength() );
nPos = csReturing.Find("\r\n");
if ( nPos < 0 ) return "";
csReturing = csReturing.Left(nPos);
csReturing.TrimLeft();
csReturing.TrimRight();

return csReturing;
}

//
// 将 HTTP 服务器表示的时间转换为 CTime 格式,如:Wed, 16 May 2007 14:29:53 GMT
//
CTime CDownloadHttp::ConvertHttpTimeString(CString csTimeGMT)
{
CString csYear, csMonth, csDay, csTime;
CTime tReturning = -1;
int nPos = csTimeGMT.Find ( ",", 0 );
if ( nPos < 0 || nPos >= csTimeGMT.GetLength()-1 )
return tReturning;
csTimeGMT = csTimeGMT.Mid ( nPos + 1 );
csTimeGMT.TrimLeft(); csTimeGMT.TrimRight ();

// 日
nPos = csTimeGMT.Find ( " ", 0 );
if ( nPos < 0 || nPos >= csTimeGMT.GetLength()-1 )
return tReturning;
csDay = csTimeGMT.Left ( nPos );
csTimeGMT = csTimeGMT.Mid ( nPos + 1 );
csTimeGMT.TrimLeft(); csTimeGMT.TrimRight ();

// 月
nPos = csTimeGMT.Find ( " ", 0 );
if ( nPos < 0 || nPos >= csTimeGMT.GetLength()-1 )
return tReturning;
csMonth = csTimeGMT.Left ( nPos );
int nMonth = GetMouthByShortStr ( csMonth );
ASSERT ( nMonth >= 1 && nMonth <= 12 );
csMonth.Format ( "%02d", nMonth );
csTimeGMT = csTimeGMT.Mid ( nPos + 1 );
csTimeGMT.TrimLeft(); csTimeGMT.TrimRight ();

// 年
nPos = csTimeGMT.Find ( " ", 0 );
if ( nPos < 0 || nPos >= csTimeGMT.GetLength()-1 )
return tReturning;
csYear = csTimeGMT.Left ( nPos );
csTimeGMT = csTimeGMT.Mid ( nPos + 1 );
csTimeGMT.TrimLeft(); csTimeGMT.TrimRight ();

// 时间
nPos = csTimeGMT.Find ( " ", 0 );
if ( nPos < 0 || nPos >= csTimeGMT.GetLength()-1 )
return tReturning;
csTime = csTimeGMT.Left ( nPos );
csTimeGMT = csTimeGMT.Mid ( nPos + 1 );

CString csFileTimeInfo;
csFileTimeInfo.Format ( "%s-%s-%s %s", csYear, csMonth, csDay, csTime );
ConvertStrToCTime ( csFileTimeInfo.GetBuffer(0), tReturning );
return tReturning;
}

分享到:
评论

相关推荐

    用VC++实现通用的报表控件C++源代码程序小实例visual studio.net

    用VC++实现通用的报表控件C++源代码程序小实例visual studio.net

    FTPserver VC++6.0开发环境

    国外人写的FTPserver FTPserver VC++6.0开发环境

    用VC++制作一个通用高校科研管理系统

    高校科研是高校面临的一项重要任务,科研管理内容也比较复杂,科研涉及的内容极广泛,面临项目、资金和人员的管理,因此制作一个通用的高校科研管理系统是十分重要的和必要的。

    用VC++实现USB接口读写数据的程序

    一个用VC++实现USB接口读写数据的程序

    VC++文件操作通用类

    一个通用文件操作类。实现很多基本的操作。使VC对文件的操作简单很多,就像使用VB一样简单。

    利用VC++实现局域网实时视频传输

    利用VC++实现局域网实时视频传输 论文形式提供实现方法

    VC++实现局域网实时视频传输

    针对不同的局域网,提出一种通用的实时...在使用Divx编解码的基础上,提出了从压缩、组帧、发送到接收、解压整个流程的思想,具体实施方案和VC++实现核心源代码以及传输控制策略,有效地保证了高质量的实时视频传输。

    vc++ 应用源码包_3

    VC++实现网络连接查看器源码 非常好的一个实例,把网络连接的UDP/TCP都插入到CList控件中显示出来。 VC++视频捕捉系统 win32下 视频操作。 VC++视频会议系统(完整)有开发文档。使用了系统自带的视频。 Windows...

    VC++界面编程通用控件26个实例源代码

    软件介绍: VC++界面编程通用控件26个实例源代码0551493926个VC++界面编程通用控件源代码实例:  如何获得指定点的控件指针  如何将编辑框中输入的字符转换为大写(小写)  如何设置和获得单选按钮的选中状态  ...

    VC++通用GIS功能开发解决方案

    VC++通用GIS功能开发解决方案》源代码是基于VC++6.0 MFC 类库,在Win2000平台上开发的。界面部分用到了较低版本的 CJ60Lib 开放源码库,用户可自行替换高版本或其他界面库,它不作为本方案的商业部分。 《VC++...

    VC++ Access数据库通用权限管理模块

    通用权限管理模块的设计与实现,基于VC++与Access,源代码可在VC++6.0下直接编译生成。  本模块主要用于软件项目中,用以给不同的用户划分权限,同时增加用户,设置他们是否超级管理员、普通管理员或系统操作员等,...

    用VC++编写人机接口类通信程序

    通过对VC6.0环境下调用API函数方法的说明,来描述如何实现与符合HID设备类 的USB设备接口的通信.并指出了在VC中调用API函数的注意事项和方法,该方法具有很强的通用性,并经过实践证明具有很好的实用性*

    vc++ 应用源码包_1

    VC++实现网络连接查看器源码 非常好的一个实例,把网络连接的UDP/TCP都插入到CList控件中显示出来。 VC++视频捕捉系统 win32下 视频操作。 VC++视频会议系统(完整)有开发文档。使用了系统自带的视频。 Windows...

    郁金香VC++初级、中级、进阶、高级+过驱动保护全套教程(已过期)

    1.1.2 用VC++写个最简单的外挂(实现游戏开局) a、鼠拟鼠标单击mouse_event b、鼠标指针移动还原 c、集成到startgame函数里 1.2、用CE查找棋盘数据 1.2.1、CE中的数据类型 a、数据类型:Bit,Byte,Word,...

    VC++2010权威开发指南+源代码.part2

     1.2 Visual C++ 2010下载安装指南 1  1.3 Visual C++ 2010主要特点与  1.3 新特性 3  1.4 Visual C++ 2010开发环境操作  1.4 指南 6  1.4.1 创建Visual C++应用程序 6  1.4.2 Visual C++ 2010菜单介绍 9  ...

    vc++ 应用源码包_5

    VC++实现网络连接查看器源码 非常好的一个实例,把网络连接的UDP/TCP都插入到CList控件中显示出来。 VC++视频捕捉系统 win32下 视频操作。 VC++视频会议系统(完整)有开发文档。使用了系统自带的视频。 Windows...

    vc++ 应用源码包_2

    VC++实现网络连接查看器源码 非常好的一个实例,把网络连接的UDP/TCP都插入到CList控件中显示出来。 VC++视频捕捉系统 win32下 视频操作。 VC++视频会议系统(完整)有开发文档。使用了系统自带的视频。 Windows...

Global site tag (gtag.js) - Google Analytics