要想从服务器下载文件,首先要向服务器发送一个请求。HTTP 请求头由若干行字符串组成。下面结合实例说说 HTTP 请求头的格式。假设要下载 http://www.sina.com.cn/index.html 这个网页 ,那么请求头的写法如下:
第1行:方法,请求的内容,HTTP协议的版本
下载一般可以用GET方法,请求的内容是“/index.html”,HTTP协议的版本是指浏览器支持的版本,对于下载软件来说无所谓,所以用1.1版 “HTTP/1.1”;
“GET /index.html HTTP/1.1”
第2行:主机名,格式为“Host:主机”
在这个例子中是:“Host:www.sina.com.cn”
第3行:接受的数据类型,下载软件当然要接收所有的数据类型,所以:
“Accept:*/*”
第4行:指定浏览器的类型
有些服务器会根据客户服务器种类的不同会增加或减少一些内容,在这个例子中可以这样写:
“User-Agent:Mozilla/4.0 (compatible; MSIE 5.00; Windows 98)”
第5行:连接设置
设定为一直保持连接:“Connection:Keep-Alive”
第6行:若要实现断点续传则要指定从什么位置起接收数据,格式如下:
“Range: bytes=起始位置 - 终止位置”
比如要读前500个字节可以这样写:“Range: bytes=0 - 499”;从第 1000 个字节起开始下载:
“Range: bytes=999 -”
最后,别忘了加上一行空行,表示请求头结束。整个请求头如下:
GET /index.html HTTP/1.1 Host:www.sina.com.cn Accept:*/* User-Agent:Mozilla/4.0 (compatible; MSIE 5.00; Windows 98) Connection:Keep-Alive
下面用例子看看如何进行断点的下载吧
// DownloadFile.h:interfacefortheCDownloadFileclass.
//
// ////////////////////////////////////////////////////////////////////
# if ! defined(AFX_DOWNLOADFILE_H__E9A59779_BEF9_4A78_8D0E_ED8C9498E07C__INCLUDED_)
#defineAFX_DOWNLOADFILE_H__E9A59779_BEF9_4A78_8D0E_ED8C9498E07C__INCLUDED_
# if _MSC_VER > 1000
#pragmaonce
#endif // _MSC_VER>1000
#defineNOTIFY_MSG_WPARAM_GENDOWNFILEID 0x01
#defineNOTIFY_MSG_LOW_WPARAM_FULLSIZE 0x10
#defineNOTIFY_MSG_LOW_WPARAM_CURRENTSIZE 0x20
#defineNOTIFY_MSG_LOW_WPARAM_DOWNSIZE 0x30
#defineNOTIFY_MSG_LOW_WPARAM_DOWNSPEED 0x40
classCDownloadFile
{
public:
BOOLOpenRedirectHttpURL(CString & strOldLocation,CInternetSession & cSession);
BOOLDownLoadFile(LPCTSTRlpFileURL,LPCTSTRlpSaveFile);
CDownloadFile();
virtual ~ CDownloadFile();
LPCTSTRGetSavedFileName(){ return m_strSaveToFile;}
LPCTSTRGetDownURL(){ return m_strFileURL;}
public:
WORDGenFileID();
void RegisterNotifyWindow(DWORDdwThreadID,HWNDhWnd,DWORDdwMsg);
BOOLGetUNCFile();
boolm_bForceReload;
DWORDm_TimeOut;
WORDm_wFileID;
protected:
DWORDm_dwThreadID;
void PostNotifyMessage(WPARAMwParam,LPARAMlParam);
DWORDm_dwMsgID;
HWNDm_hNotify;
BOOLGetFtpFile(CInternetSession & cSession);
BOOLGetHttpFile(CInternetSession & cSession);
CStringm_strTmpFileName;
CStringm_strFileURL;
CStringm_strSaveToFile;
CStringm_rawHeaders;
float m_transferRate;
DWORDm_infoStatusCode;
};
#endif // !defined(AFX_DOWNLOADFILE_H__E9A59779_BEF9_4A78_8D0E_ED8C9498E07C__INCLUDED_)
// DownloadFile.cpp:implementationoftheCDownloadFileclass.
//
// ////////////////////////////////////////////////////////////////////
#include " stdafx.h "
#include " DownloadFile.h "
#pragmacomment(lib, " Wininet.lib " )
#include " shlwapi.h "
#pragmacomment(lib, " shlwapi.lib " )
#ifdef_DEBUG
#undefTHIS_FILE
static char THIS_FILE[] = __FILE__;
#define new DEBUG_NEW
#endif
#defineBUFFER_SIZE 4095
constTCHARszHeaders[] = _T( " Accept:*/*\r\nUser-Agent:Mozilla/4.0(compatible;MSIE5.00;Windows98)\r\n " );
// ////////////////////////////////////////////////////////////////////
// Construction/Destruction
// ////////////////////////////////////////////////////////////////////
CDownloadFile::CDownloadFile()
{
m_TimeOut = 0 ;
m_bForceReload = true ;
m_dwThreadID = 0 ;
m_hNotify = NULL;
m_dwMsgID = 0 ;
m_wFileID = 0 ;
}
CDownloadFile:: ~ CDownloadFile()
{
}
BOOLCDownloadFile::DownLoadFile(LPCTSTRlpFileURL,LPCTSTRlpSaveFile)
{
BOOLbRet = FALSE;
if ( ! ::PathIsURL(lpFileURL))
{
return bRet;
}
m_strSaveToFile = lpSaveFile;
m_strFileURL = lpFileURL;
m_strTmpFileName = lpSaveFile;
m_strTmpFileName += _T( " .df! " );
CStringstrServer,strObject;INTERNET_PORTnPort;
CStringstrAgentCaption = _T( " UpdateDownload " );
strAgentCaption += ::PathFindFileName(lpSaveFile);
DWORDdwFlags = 0 ;
InternetGetConnectedState( & dwFlags, 0 );
CInternetSessionsession(strAgentCaption, 1 ,
(dwFlags & INTERNET_CONNECTION_PROXY) == INTERNET_CONNECTION_PROXY ? INTERNET_OPEN_TYPE_PRECONFIG:INTERNET_OPEN_TYPE_PRECONFIG_WITH_NO_AUTOPROXY,
NULL,NULL, 0 );
AfxParseURL(m_strFileURL,dwFlags,strServer,strObject,nPort);
if (m_TimeOut != 0 )
session.SetOption(INTERNET_OPTION_DATA_RECEIVE_TIMEOUT,m_TimeOut);
if ( ! m_wFileID)
m_wFileID = GenFileID();
PostNotifyMessage(NOTIFY_MSG_WPARAM_GENDOWNFILEID,m_wFileID);
try
{
if (dwFlags == AFX_INET_SERVICE_HTTP)
{
bRet = GetHttpFile(session);
}
else if (dwFlags == AFX_INET_SERVICE_FTP)
{
bRet = GetFtpFile(session);
}
else if (dwFlags == AFX_INET_SERVICE_FILE)
{
if (UrlIsFileUrl(m_strFileURL))
bRet = GetUNCFile();
}
else
{
;
}
}
catch (CException * pEx)
{
TCHARszErrorMsg[MAX_PATH] = { 0 };
pEx -> GetErrorMessage(szErrorMsg,MAX_PATH);
TRACE(_T( " Exception:%s\n " ),szErrorMsg);
pEx -> Delete();
}
session.Close();
m_wFileID = 0 ;
if (bRet)
{
if ( ! ::MoveFileEx(m_strTmpFileName,m_strSaveToFile,MOVEFILE_REPLACE_EXISTING))
{
Sleep( 1000 );
::MoveFileEx(m_strTmpFileName,m_strSaveToFile,MOVEFILE_REPLACE_EXISTING);
}
}
return bRet;
}
BOOLCDownloadFile::GetHttpFile(CInternetSession & cSession)
{
BOOLbRet = FALSE;
CFilem_TmpFile;
CFileExceptionfileException;
if ( ! m_TmpFile.Open(m_strTmpFileName,
CFile::modeCreate | CFile::modeNoTruncate | CFile::modeReadWrite
| CFile::shareDenyWrite | CFile::typeBinary,
& fileException))
{
TRACE(_T( " OpenFilefailed:%d\n " ),fileException.m_cause);
return bRet;
}
CStringstrRangeQuest;
if (m_TmpFile.GetLength() > 0 )
{
PostNotifyMessage(MAKEWPARAM(NOTIFY_MSG_LOW_WPARAM_CURRENTSIZE,m_wFileID),m_TmpFile.GetLength());
m_TmpFile.SeekToEnd();
strRangeQuest.Format(_T( " %sRange:bytes=%d-\r\n " ),szHeaders,m_TmpFile.GetLength());
}
else
strRangeQuest = szHeaders;
DWORDdwCount = 0 ;
CHttpFile * pFile = NULL;
CStringstrTmpURL = m_strFileURL;
try
{
DWORDdwFlags = INTERNET_FLAG_TRANSFER_BINARY
| INTERNET_FLAG_DONT_CACHE
| INTERNET_FLAG_PRAGMA_NOCACHE
;
if (m_bForceReload){
dwFlags |= INTERNET_FLAG_RELOAD;
}
// HereFindURLFileRedirect.
// OpenRedirectHttpURL(strTmpURL,cSession);
pFile = (CHttpFile * )cSession.OpenURL(strTmpURL, 1 ,dwFlags,strRangeQuest, - 1 );
}
catch (CInternetException * e)
{
TCHARszCause[MAX_PATH] = { 0 };
e -> GetErrorMessage(szCause,MAX_PATH);
e -> Delete();
delete pFile;
pFile = NULL;
return bRet;
}
COleDateTimestartTime = COleDateTime::GetCurrentTime();
DWORDdwHttpFileSize = 0 ;
if (pFile)
{
BYTEbuffer[BUFFER_SIZE + 1 ] = { 0 };
try {
UINTnRead = 0 ;
pFile -> QueryInfo(HTTP_QUERY_CONTENT_LENGTH | HTTP_QUERY_FLAG_NUMBER,dwHttpFileSize);
PostNotifyMessage(MAKEWPARAM(NOTIFY_MSG_LOW_WPARAM_FULLSIZE,m_wFileID),dwHttpFileSize);
TRACE(_T( " TotoalLengthis%d\n " ),dwHttpFileSize);
dwCount = 0 ;
do
{
nRead = pFile -> Read(buffer,BUFFER_SIZE);
if (nRead > 0 )
{
buffer[nRead] = 0 ;
m_TmpFile.Write(buffer,nRead);
COleDateTimeSpanelapsed = COleDateTime::GetCurrentTime() - startTime;
double dSecs = elapsed.GetTotalSeconds();
PostNotifyMessage(MAKEWPARAM(NOTIFY_MSG_LOW_WPARAM_DOWNSIZE,m_wFileID),dwCount);
if (dSecs > 0.0 )
{
dwCount += nRead;
m_transferRate = ( float )(dwCount / 1024.0 / dSecs);
TRACE( " Read%dbytes(%0.1fKb/s)\n " ,dwCount,m_transferRate);
}
else
{
TRACE( " Read%dbytes\n " ,dwCount);
m_transferRate = ( float )(dwCount / 1024.0 );
}
PostNotifyMessage(MAKEWPARAM(NOTIFY_MSG_LOW_WPARAM_DOWNSPEED,m_wFileID),(LPARAM)m_transferRate);
}
}
while (nRead > 0 );
bRet = TRUE;
}
catch (CFileException * e)
{
TCHARszCause[MAX_PATH] = { 0 };
e -> GetErrorMessage(szCause,MAX_PATH);
TRACE( " ErrorMsg:%s\n " ,szCause);
e -> Delete();
delete pFile;
m_TmpFile.Close();
return FALSE;
}
pFile -> QueryInfoStatusCode(m_infoStatusCode);
pFile -> QueryInfo(HTTP_QUERY_RAW_HEADERS,m_rawHeaders);
pFile -> Close();
m_TmpFile.Close();
delete pFile;
}
return bRet;
}
BOOLCDownloadFile::OpenRedirectHttpURL(CString & strOldLocation,CInternetSession & cSession)
{
BOOLbRet = FALSE;
CHttpFile * pFile = NULL;
CHttpConnection * pServer = NULL;
CStringstrServerName,strObject;
INTERNET_PORTnPort = 0 ;
DWORDdwServiceType = 0 ;
if ( ! AfxParseURL(strOldLocation,dwServiceType,strServerName,strObject,nPort) ||
dwServiceType != INTERNET_SERVICE_HTTP)
{
TRACE(_T( " NotAHttpQuest!\n " ));
return bRet;
}
pServer = cSession.GetHttpConnection(strServerName,nPort);
pFile = pServer -> OpenRequest(CHttpConnection::HTTP_VERB_GET,
strObject,NULL, 1 ,NULL,NULL,
INTERNET_FLAG_EXISTING_CONNECT | INTERNET_FLAG_NO_AUTO_REDIRECT);
pFile -> AddRequestHeaders(szHeaders);
pFile -> SendRequest();
DWORDdwRet;
pFile -> QueryInfoStatusCode(dwRet);
// ifaccesswasdenied,prompttheuserforthepassword
if (dwRet == HTTP_STATUS_DENIED)
{
DWORDdwPrompt;
dwPrompt = pFile -> ErrorDlg(NULL,ERROR_INTERNET_INCORRECT_PASSWORD,
FLAGS_ERROR_UI_FLAGS_GENERATE_DATA | FLAGS_ERROR_UI_FLAGS_CHANGE_OPTIONS,NULL);
// iftheusercancelledthedialog,bailout
if (dwPrompt != ERROR_INTERNET_FORCE_RETRY)
{
TRACE(_T( " Accessdenied:Invalidpassword\n " ));
// closeuptheredirectedsite
pFile -> Close();
delete pFile;
pServer -> Close();
delete pServer;
return bRet;
}
pFile -> SendRequest();
pFile -> QueryInfoStatusCode(dwRet);
}
// wereweredirected?
// theseresponsestatuscodescomefromWININET.H
if (dwRet == HTTP_STATUS_MOVED ||
dwRet == HTTP_STATUS_REDIRECT ||
dwRet == HTTP_STATUS_REDIRECT_METHOD)
{
CStringstrNewLocation;
pFile -> QueryInfo(HTTP_QUERY_RAW_HEADERS_CRLF,strNewLocation);
int nPlace = strNewLocation.Find(_T( " Location: " ));
if (nPlace == - 1 )
{
TRACE(_T( " Error:Siteredirectswithnonewlocation\n " ));
// closeuptheredirectedsite
pFile -> Close();
delete pFile;
pServer -> Close();
delete pServer;
return bRet;
}
strNewLocation = strNewLocation.Mid(nPlace + 10 );
nPlace = strNewLocation.Find('\n');
if (nPlace > 0 )
strNewLocation = strNewLocation.Left(nPlace);
strOldLocation = strNewLocation;
}
if (dwRet == HTTP_STATUS_OK)
{
bRet = TRUE;
}
// closeuptheredirectedsite
pFile -> Close();
delete pFile;
pServer -> Close();
delete pServer;
return bRet;
}
BOOLCDownloadFile::GetFtpFile(CInternetSession & cSession)
{
BOOLbRet = FALSE;
CFilem_TmpFile;
CFileExceptionfileException;
if ( ! m_TmpFile.Open(m_strTmpFileName,
CFile::modeCreate | CFile::modeNoTruncate | CFile::modeReadWrite
| CFile::shareDenyWrite | CFile::typeBinary,
& fileException))
{
TRACE(_T( " OpenFilefailed:%d\n " ),fileException.m_cause);
return bRet;
}
DWORDdwCount = 0 ;
CFtpConnection * pFtpConn = NULL;
CInternetFile * pFile = NULL;
try
{
CStringstrServerName,strObject,strUserName,strPassword;
INTERNET_PORTnPort = 0 ;
DWORDdwServiceType = 0 ;
CStringstrRestPointCommand;
if ( ! AfxParseURLEx(m_strFileURL,dwServiceType,strServerName,strObject,nPort,
strUserName,strPassword) ||
dwServiceType != INTERNET_SERVICE_FTP)
{
TRACE(_T( " NotAFtpQuest!\n " ));
}
// CFtpConnectionERROR_INTERNET_NO_DIRECT_ACCESSCInternetSession
if (strUserName.IsEmpty())
pFtpConn = cSession.GetFtpConnection(strServerName,NULL,NULL,nPort,m_bForceReload);
else
pFtpConn = cSession.GetFtpConnection(strServerName,strUserName,strPassword,nPort,m_bForceReload);
if (m_TmpFile.GetLength())
{
PostNotifyMessage(MAKEWPARAM(NOTIFY_MSG_LOW_WPARAM_CURRENTSIZE,m_wFileID),m_TmpFile.GetLength());
m_TmpFile.SeekToEnd();
strRestPointCommand.Format(_T( " REST%d " ),m_TmpFile.GetLength());
// strRestPointCommand.Format(_T("ls"));
if ( ! FtpCommand(( * pFtpConn),FALSE,FTP_TRANSFER_TYPE_ASCII,
strRestPointCommand, 0 , 0 ))
{
TRACE(_T( " FtpCommandfailed,error:%d\n " ),GetLastError());
m_TmpFile.SeekToBegin();
}
}
if (pFtpConn)
{
pFile = pFtpConn -> OpenFile(strObject);
}
}
catch (CInternetException * e)
{
TCHARszCause[MAX_PATH] = { 0 };
e -> GetErrorMessage(szCause,MAX_PATH);
e -> Delete();
delete pFile;
delete pFtpConn;
return bRet;
}
COleDateTimestartTime = COleDateTime::GetCurrentTime();
DWORDdwFtpFileSize = 0 ;
if (pFile)
{
BYTEbuffer[BUFFER_SIZE + 1 ] = { 0 };
try {
UINTnRead = 0 ;
dwFtpFileSize = FtpGetFileSize(( * pFile), 0 );
PostNotifyMessage(MAKEWPARAM(NOTIFY_MSG_LOW_WPARAM_FULLSIZE,m_wFileID),dwFtpFileSize);
TRACE(_T( " TotoalLengthis%d\n " ),dwFtpFileSize);
dwCount = 0 ;
do
{
nRead = pFile -> Read(buffer,BUFFER_SIZE);
if (nRead > 0 )
{
buffer[nRead] = 0 ;
m_TmpFile.Write(buffer,nRead);
COleDateTimeSpanelapsed = COleDateTime::GetCurrentTime() - startTime;
double dSecs = elapsed.GetTotalSeconds();
PostNotifyMessage(MAKEWPARAM(NOTIFY_MSG_LOW_WPARAM_DOWNSIZE,m_wFileID),dwCount);
if (dSecs > 0.0 )
{
dwCount += nRead;
m_transferRate = ( float )(dwCount / 1024.0 / dSecs);
TRACE( " Read%dbytes(%0.1fKb/s)\n " ,dwCount,m_transferRate);
}
else
{
TRACE( " Read%dbytes\n " ,dwCount);
m_transferRate = ( float )(dwCount / 1024.0 );
}
PostNotifyMessage(MAKEWPARAM(NOTIFY_MSG_LOW_WPARAM_DOWNSPEED,m_wFileID),(LPARAM)m_transferRate);
}
}
while (nRead > 0 );
bRet = TRUE;
}
catch (CFileException * e)
{
TCHARszCause[MAX_PATH] = { 0 };
e -> GetErrorMessage(szCause,MAX_PATH);
TRACE( " ErrorMsg:%s\n " ,szCause);
e -> Delete();
delete pFile;
pFtpConn -> Close();
delete pFtpConn;
m_TmpFile.Close();
return FALSE;
}
pFile -> Close();
delete pFile;
m_TmpFile.Close();
pFtpConn -> Close();
delete pFtpConn;
}
return bRet;
}
BOOLCDownloadFile::GetUNCFile()
{
BOOLbRet = FALSE;
CFilem_TmpFile,m_SrcFile;
CFileExceptionfileException;
CStringstrOldLocation = m_strFileURL;
if ( ! m_TmpFile.Open(m_strTmpFileName,
CFile::modeCreate | CFile::modeNoTruncate | CFile::modeReadWrite
| CFile::shareDenyWrite | CFile::typeBinary,
& fileException))
{
TRACE(_T( " OpenFilefailed:%d\n " ),fileException.m_cause);
return bRet;
}
strOldLocation.TrimLeft();
strOldLocation.TrimRight();
if (StrCmpNI(strOldLocation,_T( " file:/ " ), 6 ) == 0 )
{
strOldLocation = strOldLocation.Mid( 8 );
strOldLocation.Replace(_T(' / '),_T('\\'));
}
if ( ! m_SrcFile.Open(strOldLocation,
CFile::modeRead | CFile::shareDenyWrite | CFile::typeBinary,
& fileException))
{
TRACE(_T( " OpenFilefailed:%d\n " ),fileException.m_cause);
return bRet;
}
COleDateTimestartTime = COleDateTime::GetCurrentTime();
DWORDdwCount = 0 ;
try {
if (m_TmpFile.GetLength())
{
PostNotifyMessage(MAKEWPARAM(NOTIFY_MSG_LOW_WPARAM_CURRENTSIZE,m_wFileID),m_TmpFile.GetLength());
m_TmpFile.SeekToEnd();
m_SrcFile.Seek(m_TmpFile.GetLength(),CFile::begin);
}
BYTEbuffer[BUFFER_SIZE + 1 ] = { 0 };
UINTnRead = 0 ;
PostNotifyMessage(MAKEWPARAM(NOTIFY_MSG_LOW_WPARAM_FULLSIZE,m_wFileID),m_SrcFile.GetLength());
TRACE(_T( " TotoalLengthis%d,leftis%d\n " ),m_SrcFile.GetLength(),m_SrcFile.GetLength() - m_TmpFile.GetLength());
dwCount = 0 ;
do
{
nRead = m_SrcFile.Read(buffer,BUFFER_SIZE);
if (nRead > 0 )
{
buffer[nRead] = 0 ;
m_TmpFile.Write(buffer,nRead);
COleDateTimeSpanelapsed = COleDateTime::GetCurrentTime() - startTime;
double dSecs = elapsed.GetTotalSeconds();
PostNotifyMessage(MAKEWPARAM(NOTIFY_MSG_LOW_WPARAM_DOWNSIZE,m_wFileID),dwCount);
if (dSecs > 0.0 )
{
dwCount += nRead;
m_transferRate = ( float )(dwCount / 1024.0 / dSecs);
TRACE( " Read%dbytes(%0.1fKb/s)\n " ,dwCount,m_transferRate);
}
else
{
TRACE( " Read%dbytes\n " ,dwCount);
m_transferRate = ( float )(dwCount / 1024.0 );
}
PostNotifyMessage(MAKEWPARAM(NOTIFY_MSG_LOW_WPARAM_DOWNSPEED,m_wFileID),(LPARAM)m_transferRate);
}
}
while (nRead > 0 );
bRet = TRUE;
}
catch (CFileException * e)
{
TCHARszCause[MAX_PATH] = { 0 };
e -> GetErrorMessage(szCause,MAX_PATH);
TRACE( " ErrorMsg:%s\n " ,szCause);
e -> Delete();
m_TmpFile.Close();
return FALSE;
}
m_TmpFile.Close();
return bRet;
}
void CDownloadFile::RegisterNotifyWindow(DWORDdwThreadID,HWNDhWnd,DWORDdwMsg)
{
m_dwThreadID = dwThreadID;
m_hNotify = hWnd;
m_dwMsgID = dwMsg;
}
void CDownloadFile::PostNotifyMessage(WPARAMwParam,LPARAMlParam)
{
if (m_hNotify)
{
::PostMessage(m_hNotify,m_dwMsgID,wParam,lParam);
}
if (m_dwThreadID)
{
::PostThreadMessage(m_dwThreadID,m_dwMsgID,wParam,lParam);
}
}
WORDCDownloadFile::GenFileID()
{
srand(GetTickCount());
return rand() & 0xFFFF ;
}