1)Because we need use windows socket to get http page,we need initialise win socket
At the beginning of our application,we should do below:
int err;
WORD wVersion;
WSADATA WSAData;
wVersion=MAKEWORD(2,0);
err=WSAStartup(wVersion,&WSAData);
if(err!=0)
{
AfxMessageBox("无法装载Socket库.");
}
if(LOBYTE( WSAData.wVersion ) != 2)
{
AfxMessageBox("无法找到合适的Socket库.");
WSACleanup();
}
After all aplication finished,we should do below:
WSACleanup();
2)how to download
downLoadHttp.strFileName="c:/1.html";
downLoadHttp.m_strRequest="http://www.baidu.com";
downLoadHttp.Start();
At the beginning of our application,we should do below:
int err;
WORD wVersion;
WSADATA WSAData;
wVersion=MAKEWORD(2,0);
err=WSAStartup(wVersion,&WSAData);
if(err!=0)
{
AfxMessageBox("无法装载Socket库.");
}
if(LOBYTE( WSAData.wVersion ) != 2)
{
AfxMessageBox("无法找到合适的Socket库.");
WSACleanup();
}
After all aplication finished,we should do below:
WSACleanup();
2)how to download
downLoadHttp.strFileName="c:/1.html";
downLoadHttp.m_strRequest="http://www.baidu.com";
downLoadHttp.Start();
- // DownLoadHttp.h: interface for the CDownLoadHttp class.
- //
- //
- #if !defined(AFX_DOWNLOADHTTP_H__1E0699F1_CFD6_461B_BBF6_44A8A6A4E269__INCLUDED_)
- #define AFX_DOWNLOADHTTP_H__1E0699F1_CFD6_461B_BBF6_44A8A6A4E269__INCLUDED_
- #if _MSC_VER > 1000
- #pragma once
- #endif // _MSC_VER > 1000
- //
- // 单个对象的下载信息
- //
- typedef struct _downloadcellinfo
- {
- int nWillDownloadStartPos; // 要下载文件的开始位置
- int nWillDownloadSize; // 本次需要下载的大小,-1表示一直下载到文件尾
- DWORD nDownloadedSize; // 该线程已下载的大小
- } t_DownloadCellInfo;
- class CDownLoadHttp
- {
- public:
- CDownLoadHttp();
- virtual ~CDownLoadHttp();
- DWORD CDownLoadHttp::GetDownloadElapsedTime();//获取已下载的时间
- CString CDownLoadHttp::FormatFileSize ( double fFileSize );//计算速度
- UINT DownloadThread(); //下载
- void BeginDownLoad(void *pArg);
- void Start();
- void Suspend();
- void Stop2();
- CString strFileName;
- CString m_strRequest;
- CHttpSocket HttpSocket;
- HANDLE m_hThread; //线程句柄
- t_DownloadCellInfo *m_pDownloadCellInfo; //下载对象参数
- DWORD m_dwDownloadStartTime; //开始时间
- int nCompletedSize ;
- bool bSuspend;
- CFile DownloadFile;
- };
- #endif // !defined(AFX_DOWNLOADHTTP_H__1E0699F1_CFD6_461B_BBF6_44A8A6A4E269__INCLUDED_)
- // HttpSocket.cpp: implementation of the CHttpSocket class.
- //
- //
- #include "stdafx.h"
- #include "HttpSocket.h"
- #ifdef _DEBUG
- #undef THIS_FILE
- static char THIS_FILE[]=__FILE__;
- #define new DEBUG_NEW
- #endif
- #define MAXHEADERSIZE 1024
- //
- // Construction/Destruction
- //
- CHttpSocket::CHttpSocket()
- {
- m_s=NULL;
- m_phostent=NULL;
- m_port=80;
- m_bConnected=FALSE;
- for(int i=0;i<256;i++)
- m_ipaddr[i]='/0';
- memset(m_requestheader,0,MAXHEADERSIZE);
- memset(m_ResponseHeader,0,MAXHEADERSIZE);
- m_nCurIndex = 0; //
- m_bResponsed = FALSE;
- m_nResponseHeaderSize = -1;
- /*
- m_nBufferSize = nBufferSize;
- m_pBuffer = new char[nBufferSize];
- memset(m_pBuffer,0,nBufferSize);*/
- }
- CHttpSocket::~CHttpSocket()
- {
- CloseSocket();
- }
- BOOL CHttpSocket::Socket()
- {
- if(m_bConnected)return FALSE;
- struct protoent *ppe;
- ppe=getprotobyname("tcp");
- ///创建SOCKET对象
- m_s=socket(PF_INET,SOCK_STREAM,ppe->p_proto);
- if(m_s==INVALID_SOCKET)
- {
- MessageBox(NULL,"socket()函数执行失败!","错误",MB_OK);
- return FALSE;
- }
- return TRUE;
- }
- BOOL CHttpSocket::Connect(char *szHostName,int nPort)
- {
- if(szHostName==NULL)
- return FALSE;
- ///若已经连接,则先关闭
- if(m_bConnected)
- {
- CloseSocket();
- }
- ///保存端口号
- m_port=nPort;
- ///根据主机名获得IP地址
- m_phostent=gethostbyname(szHostName);
- if(m_phostent==NULL)
- {
- MessageBox(NULL,"gethostbyname()函数执行失败!","错误",MB_OK);
- return FALSE;
- }
- ///连接
- struct in_addr ip_addr;
- memcpy(&ip_addr,m_phostent->h_addr_list[0],4);///h_addr_list[0]里4个字节,每个字节8位
- struct sockaddr_in destaddr;
- memset((void *)&destaddr,0,sizeof(destaddr));
- destaddr.sin_family=AF_INET;
- destaddr.sin_port=htons(nPort);
- destaddr.sin_addr=ip_addr;
- ///保存主机的IP地址字符串
- sprintf(m_ipaddr,"%d.%d.%d.%d",
- destaddr.sin_addr.S_un.S_un_b.s_b1,
- destaddr.sin_addr.S_un.S_un_b.s_b2,
- destaddr.sin_addr.S_un.S_un_b.s_b3,
- destaddr.sin_addr.S_un.S_un_b.s_b4);
- /*inet_addr();把带点的IP地址字符串转化为in_addr格式;
- inet_ntoa();作用相反*/
- /*注意理解sturct in_addr 的结构:一个32位的数;一共同体的形式使用
- (1)每8位一个即s_b1~s_b4;
- (2)每16位一个即s_w1~s_w2;
- (3)32位s_addr
- struct in_addr {
- union {
- struct{
- unsigned char s_b1,
- s_b2,
- s_b3,
- s_b4;
- } S_un_b;
- struct{
- unsigned short s_w1,
- s_w2
- }S_un_w;
- unsigned long S_addr;
- } S_un;
- };
- */
- if(connect(m_s,(struct sockaddr*)&destaddr,sizeof(destaddr))!=0)
- {
- //CloseSocket();
- //m_s=NULL;
- MessageBox(NULL,"connect()函数执行失败!","错误",MB_OK);
- return FALSE;
- }
- ///设置已经连接的标志
- m_bConnected=TRUE;
- return TRUE;
- }
- ///根据请求的相对URL输出HTTP请求头
- const char *CHttpSocket::FormatRequestHeader(char *pServer,char *pObject, long &Length,
- char *pCookie,char *pReferer,long nFrom,
- long nTo,int nServerType)
- {
- char szPort[10];
- char szTemp[20];
- sprintf(szPort,"%d",m_port);
- memset(m_requestheader,'/0',1024);
- ///第1行:方法,请求的路径,版本
- strcat(m_requestheader,"GET ");
- strcat(m_requestheader,pObject);
- strcat(m_requestheader," HTTP/1.1");
- strcat(m_requestheader,"/r/n");
- ///第2行:主机
- strcat(m_requestheader,"Host:");
- strcat(m_requestheader,pServer);
- strcat(m_requestheader,"/r/n");
- ///第3行:
- if(pReferer != NULL)
- {
- strcat(m_requestheader,"Referer:");
- strcat(m_requestheader,pReferer);
- strcat(m_requestheader,"/r/n");
- }
- ///第4行:接收的数据类型
- strcat(m_requestheader,"Accept:*/*");
- strcat(m_requestheader,"/r/n");
- ///第5行:浏览器类型
- strcat(m_requestheader,"User-Agent:Mozilla/4.0 (compatible; MSIE 5.00; Windows 98)");
- strcat(m_requestheader,"/r/n");
- ///第6行:连接设置,保持
- strcat(m_requestheader,"Connection:Keep-Alive");
- strcat(m_requestheader,"/r/n");
- ///第7行:Cookie.
- if(pCookie != NULL)
- {
- strcat(m_requestheader,"Set Cookie:0");
- strcat(m_requestheader,pCookie);
- strcat(m_requestheader,"/r/n");
- }
- ///第8行:请求的数据起始字节位置(断点续传的关键)
- if(nFrom > 0)
- {
- strcat(m_requestheader,"Range: bytes=");
- _ltoa(nFrom,szTemp,10);
- strcat(m_requestheader,szTemp);
- strcat(m_requestheader,"-");
- if(nTo > nFrom)
- {
- _ltoa(nTo,szTemp,10);
- strcat(m_requestheader,szTemp);
- }
- strcat(m_requestheader,"/r/n");
- }
- ///最后一行:空行
- strcat(m_requestheader,"/r/n");
- ///返回结果
- Length=strlen(m_requestheader);
- return m_requestheader;
- }
- ///发送请求头
- BOOL CHttpSocket::SendRequest(const char *pRequestHeader, long Length)
- {
- if(!m_bConnected)return FALSE;
- if(pRequestHeader==NULL)
- pRequestHeader=m_requestheader;
- if(Length==0)
- Length=strlen(m_requestheader);
- if(send(m_s,pRequestHeader,Length,0)==SOCKET_ERROR)
- {
- MessageBox(NULL,"send()函数执行失败!","错误",MB_OK);
- return FALSE;
- }
- int nLength;
- GetResponseHeader(nLength);
- return TRUE;
- }
- long CHttpSocket::Receive(char* pBuffer,long nMaxLength)
- {
- if(!m_bConnected)return NULL;
- ///接收数据
- long nLength;
- nLength=recv(m_s,pBuffer,nMaxLength,0);
- if(nLength <= 0)
- {
- //MessageBox(NULL,"recv()函数执行失败!","错误",MB_OK);
- CloseSocket();
- }
- return nLength;
- }
- ///关闭套接字
- BOOL CHttpSocket::CloseSocket()
- {
- if(m_s != NULL)
- {
- if(closesocket(m_s)==SOCKET_ERROR)
- {
- MessageBox(NULL,"closesocket()函数执行失败!","错误",MB_OK);
- return FALSE;
- }
- }
- m_s = NULL;
- m_bConnected=FALSE;
- return TRUE;
- }
- int CHttpSocket::GetRequestHeader(char *pHeader, int nMaxLength) const
- {
- int nLength;
- if(int(strlen(m_requestheader))>nMaxLength)
- {
- nLength=nMaxLength;
- }
- else
- {
- nLength=strlen(m_requestheader);
- }
- memcpy(pHeader,m_requestheader,nLength);
- return nLength;
- }
- //设置接收或者发送的最长时间
- BOOL CHttpSocket::SetTimeout(int nTime, int nType)
- {
- if(nType == 0)
- {
- nType = SO_RCVTIMEO;
- }
- else
- {
- nType = SO_SNDTIMEO;
- }
- DWORD dwErr;
- dwErr=setsockopt(m_s,SOL_SOCKET,nType,(char*)&nTime,sizeof(nTime));
- if(dwErr)
- {
- MessageBox(NULL,"setsockopt()函数执行失败!","错误",MB_OK);
- return FALSE;
- }
- return TRUE;
- }
- //获取HTTP请求的返回头
- const char* CHttpSocket::GetResponseHeader(int &nLength)
- {
- // if(!m_bResponsed)
- {
- char c = 0;
- int nIndex = 0;
- m_nResponseHeaderSize=-1;
- BOOL bEndResponse = FALSE;
- while(!bEndResponse && nIndex < MAXHEADERSIZE)
- {
- recv(m_s,&c,1,0);
- m_ResponseHeader[nIndex++] = c;
- if(nIndex >= 4)
- {
- if(m_ResponseHeader[0]!='H'&&m_ResponseHeader[1]!='T'
- &&m_ResponseHeader[2]!='T'&&m_ResponseHeader[3]!='P')
- {
- AfxMessageBox("返回信息有误,下载中止");
- CloseSocket();
- break;
- }
- if(m_ResponseHeader[nIndex - 4] == '/r' && m_ResponseHeader[nIndex - 3] == '/n'
- && m_ResponseHeader[nIndex - 2] == '/r' && m_ResponseHeader[nIndex - 1] == '/n')
- bEndResponse = TRUE;
- }
- }
- m_nResponseHeaderSize = nIndex;
- m_ResponseHeader[nIndex]=NULL;
- m_bResponsed = TRUE;
- }
- nLength = m_nResponseHeaderSize;
- return m_ResponseHeader;
- }
- //返回HTTP响应头中的一行.
- int CHttpSocket::GetResponseLine(char *pLine, int nMaxLength)
- {
- if(m_nCurIndex >= m_nResponseHeaderSize)
- {
- m_nCurIndex = 0;
- return -1;
- }
- int nIndex = 0;
- char c = 0;
- do
- {
- c = m_ResponseHeader[m_nCurIndex++];
- pLine[nIndex++] = c;
- } while(c != '/n' && m_nCurIndex < m_nResponseHeaderSize && nIndex < nMaxLength);
- return nIndex;
- }
- int CHttpSocket::GetField(const char *szSession, char *szValue, int nMaxLength)
- {
- //取得某个域值
- if(!m_bResponsed) return -1;
- CString strRespons;
- strRespons = m_ResponseHeader;
- int nPos = -1;
- nPos = strRespons.Find(szSession,0);
- if(nPos != -1)
- {
- nPos += strlen(szSession);
- nPos += 2;
- int nCr = strRespons.Find("/r/n",nPos);
- CString strValue = strRespons.Mid(nPos,nCr - nPos);
- strcpy(szValue,strValue);
- return (nCr - nPos);
- }
- else
- {
- return -1;
- }
- }
- int CHttpSocket::GetServerState()
- {
- //若没有取得响应头,返回失败
- if(!m_bResponsed) return -1;
- char szState[3];
- szState[0] = m_ResponseHeader[9];
- szState[1] = m_ResponseHeader[10];
- szState[2] = m_ResponseHeader[11];
- return atoi(szState);
- }
- // HttpSocket.h: interface for the CHttpSocket class.
- //
- //
- #if !defined(AFX_HTTPSOCKET_H__F49A8F82_A933_41A8_AF47_68FBCAC4ADA6__INCLUDED_)
- #define AFX_HTTPSOCKET_H__F49A8F82_A933_41A8_AF47_68FBCAC4ADA6__INCLUDED_
- #include "winsock2.h"
- #include <afxinet.h>
- #include <afxsock.h>
- #if _MSC_VER > 1000
- #pragma once
- #endif // _MSC_VER > 1000
- class _declspec(dllexport) CHttpSocket :public CSocket
- {
- public:
- int GetServerState(); //返回服务器状态码 -1表示不成功
- int GetField(const char* szSession,char *szValue,int nMaxLength); //返回某个域值,-1表示不成功
- int GetResponseLine(char *pLine,int nMaxLength); //获取返回头的一行
- const char* GetResponseHeader(int &Length); //获取完整的返回头
- const char * FormatRequestHeader(char *pServer,char *pObject,long &Length,
- char* pCookie=NULL,char *pReferer=NULL,
- long nFrom=0,long nTo=0,
- int nServerType=0); //格式化请求头
- int GetRequestHeader(char *pHeader,int nMaxLength) const;
- BOOL SendRequest(const char* pRequestHeader = NULL,long Length = 0);
- CHttpSocket();
- virtual ~CHttpSocket();
- BOOL SetTimeout(int nTime,int nType=0);
- long Receive(char* pBuffer,long nMaxLength);
- BOOL Connect(char* szHostName,int nPort=80);
- BOOL Socket();
- BOOL CloseSocket();
- char m_ResponseHeader[1024]; //回应头
- protected:
- char m_requestheader[1024]; //请求头
- int m_port; //端口
- char m_ipaddr[256]; //IP地址
- BOOL m_bConnected;
- SOCKET m_s;
- hostent *m_phostent;
- int m_nCurIndex; //GetResponsLine()函数的游标记录
- BOOL m_bResponsed; //是否已经取得了返回头
- int m_nResponseHeaderSize; //回应头的大小
- /*
- int m_nBufferSize;
- char *m_pBuffer;*/
- };
- #endif // !defined(AFX_HTTPSOCKET_H__F49A8F82_A933_41A8_AF47_68FBCAC4ADA6__INCLUDED_)
- // DownLoadHttp.cpp: implementation of the CDownLoadHttp class.
- //
- //
- #include "stdafx.h"
- #include "HttpSocket.h"
- #include "DownLoadHttp.h"
- //#include "TestHttpDlg.h"
- #ifdef _DEBUG
- #undef THIS_FILE
- static char THIS_FILE[]=__FILE__;
- #define new DEBUG_NEW
- #endif
- //
- // Construction/Destruction
- //
- CDownLoadHttp::CDownLoadHttp()
- {
- nCompletedSize=0;
- m_hThread = NULL;
- bSuspend=false;
- }
- CDownLoadHttp::~CDownLoadHttp()
- {
- }
- //
- // 获取下载所消耗的时间(毫秒),可用来计算下载速度和推算剩余时间
- //
- DWORD CDownLoadHttp::GetDownloadElapsedTime()
- {
- return (GetTickCount() - m_dwDownloadStartTime);
- }
- UINT CDownLoadHttp::DownloadThread()
- {
- CString strServer,strObject;
- unsigned short nPort;
- DWORD dwServiceType;
- long nLength;
- // char pCookie[256]='/0';
- // char pReferer[256]='/0';
- const char *pRequestHeader = NULL;
- BOOL bIsTran=TRUE;
- int nSvrState;
- while(bIsTran)
- {
- AfxParseURL(m_strRequest,dwServiceType,strServer,strObject,nPort);
- pRequestHeader = HttpSocket.FormatRequestHeader((LPTSTR)(LPCTSTR)strServer
- ,(LPTSTR)(LPCTSTR)strObject,nLength,NULL,NULL,nCompletedSize);
- HttpSocket.Socket();
- HttpSocket.Connect((LPTSTR)(LPCTSTR)strServer,nPort);
- HttpSocket.SendRequest();
- HttpSocket.SetTimeout(10000,0);
- // HttpSocket.GetField("Cookie",pCookie,256);
- //服务器状态,(300,400)被重定向
- nSvrState = HttpSocket.GetServerState();
- if( nSvrState>= 300 && nSvrState< 400 )
- {
- char sLocal[256];
- int path=HttpSocket.GetField("Location",sLocal,256);
- bIsTran=TRUE;
- HttpSocket.CloseSocket();
- }
- else bIsTran=FALSE;
- }
- if(nSvrState<200||nSvrState>=400)
- {
- AfxMessageBox("服务器信息有错");
- return 0;
- }
- BeginDownLoad(NULL);
- return 0;
- }
- void CDownLoadHttp::BeginDownLoad(void *pArg)
- {
- char szValue[30];
- HttpSocket.GetField("Content-Length",szValue,30);
- int nFileSize = atoi(szValue);
- int iThisDown=0;
- DownloadFile.Open(strFileName,CFile::modeCreate | CFile::modeReadWrite|CFile::modeNoTruncate|CFile::shareDenyNone);
- long lposition=DownloadFile.GetPosition();
- long fileLength=DownloadFile.GetLength();
- if(nCompletedSize)lposition=DownloadFile.Seek(nCompletedSize,CFile::begin);
- char pData[1024];
- int nReceSize = 0;
- m_dwDownloadStartTime= GetTickCount();
- while(iThisDown< nFileSize)
- {
- nReceSize = HttpSocket.Receive(pData,1024);
- if(nReceSize == 0)
- {
- AfxMessageBox("服务器已经关闭连接.");
- // DownloadFile.Close();
- break;
- }
- if(nReceSize == -1)
- {
- AfxMessageBox("接收数据超时.");
- // DownloadFile.Close();
- break;
- }
- DownloadFile.Write(pData,nReceSize);
- iThisDown+=nReceSize;
- nCompletedSize += nReceSize;
- //Speed
- int nElapsedTime = this->GetDownloadElapsedTime ();
- if ( nElapsedTime > 5*1000 || ( nElapsedTime > 2*1000 && nCompletedSize > 1024*10 ) )
- {
- double dSpeed = (double)nCompletedSize / ((double)nElapsedTime / 1000.0);
- CString csSpeed = FormatFileSize ( dSpeed );
- csSpeed += "/S";
- }
- }
- if(iThisDown==nFileSize)
- {
- AfxMessageBox("Download Complete");
- }
- HttpSocket.CloseSocket();
- ::CloseHandle ( m_hThread );
- (m_hThread) = NULL;
- DownloadFile.Close();
- }
- CString CDownLoadHttp::FormatFileSize ( double fFileSize )
- {
- CString csRet;
- if ( fFileSize < 1024.0 )
- {
- csRet.Format ( "%d b", fFileSize );
- }
- else if ( fFileSize >= 1024.0 && fFileSize < 1024.0*1024.0 )
- {
- csRet.Format ( "%.2f K", fFileSize/1024.0 );
- }
- else if ( fFileSize >= 1024.0*1024.0 && fFileSize < 1024.0*1024.0*1024.0 )
- {
- csRet.Format ( "%.2f M", fFileSize/(1024.0*1024.0) );
- }
- else
- {
- csRet.Format ( "%.2f G", fFileSize/(1024.0*1024.0*1024.0) );
- }
- return csRet;
- }
- DWORD WINAPI DownloadThread(void *pArg)
- {
- CDownLoadHttp *nDownLoad=(CDownLoadHttp *)pArg;
- nDownLoad->DownloadThread();
- return 0;
- }
- void CDownLoadHttp::Start()
- {
- DWORD dwThreadId=0;
- m_hThread = CreateThread ( NULL, 0, ::DownloadThread, LPVOID(this), 0, &dwThreadId );
- if ( !m_hThread )
- {
- AfxMessageBox("Create download thread failed" );
- }
- }
- void CDownLoadHttp::Suspend()
- {
- if ( m_hThread )
- {
- /* // HttpSocket.CancelBlockingCall ();
- HttpSocket.CloseSocket();
- DWORD dwWaitTime=5000;
- if ( ::WaitForSingleObject ( m_hThread, dwWaitTime ) == WAIT_TIMEOUT )
- {
- ::TerminateThread ( m_hThread, 0 );
- }
- ::CloseHandle ( m_hThread );
- (m_hThread) = NULL;
- */
- if(!bSuspend)
- {
- SuspendThread(m_hThread);
- bSuspend=true;
- CString sSuspend;
- sSuspend.Format("Suspend %d",this->nCompletedSize);
- AfxMessageBox(sSuspend);
- }
- else
- {
- // AfxMessageBox("Resume");
- CString sResume;
- sResume.Format("Resume %d",this->nCompletedSize);
- AfxMessageBox(sResume);
- ResumeThread(m_hThread);
- bSuspend=false;
- }
- }
- else AfxMessageBox("Please download first.");
- }
- void CDownLoadHttp::Stop2()
- {
- if ( m_hThread )
- {
- // HttpSocket.CancelBlockingCall ();
- SuspendThread(m_hThread);
- HttpSocket.CloseSocket();
- DWORD dwWaitTime=500;
- if ( ::WaitForSingleObject ( m_hThread, dwWaitTime ) == WAIT_TIMEOUT )
- {
- ::TerminateThread ( m_hThread, 0 );
- }
- ::CloseHandle ( m_hThread );
- (m_hThread) = NULL;
- DownloadFile.Close();
- }
- }