// HttpClient.h: HTTP协议客户端的实现类
//
//////////////////////////////////////////////////////////////////////
#if !defined(_HTTPCLIENT_H__)
#define _HTTPCLIENT_H__
#include "../comm/tcp.h"
#pragma warning(disable : 4786)
#include <map>
#include <string>
using namespace std;
#define BUFFER_SIZE 8192
#define HEADS_BUFFER_SIZE 2048
#define PEEK_SIZE 500
#define TCP_TIMEOUT 5
class CHttpClient
{
public:
void Cancel();
const char* GetStatusString();
CHttpClient();
virtual ~CHttpClient();
bool Download(char* url,char* fname); //直接下载到文件
bool Download(char* url,HWND hParent,long msg = WM_USER+1); //消息方式下载数据流
inline long Instr(char* from,char* find);
virtual void OnDataRecived(char* data,long datasize,int first = false );
long GetHostName(char *url, char *buf);
int GetStatus();
long GetHeader(char* headname,char* buf);
long GetHeader(char* from,char* searchfor,char* buf);
bool Reset();
private:
long m_Message;
HWND m_hParent;
bool m_noCancel;
char m_fname[BUFFER_SIZE];
int m_status;
char m_heads_buffer[HEADS_BUFFER_SIZE];
char m_buffer[BUFFER_SIZE+1];
CTcp tcp;
map<const int,string> m_map;
};
#endif
//----------------------------------------------------------------
// HttpClient.cpp: implementation of the CHttpClient class.
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "HttpClient.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CHttpClient::CHttpClient()
{
Reset();
memset(m_fname,0,BUFFER_SIZE);
tcp.init();
m_map[100]= "Continue";
m_map[101]= "Switching Protocols";
m_map[200]= "OK";
m_map[201]= "Created";
m_map[202]= "Accepted";
m_map[203]= "Non-Authoritative Information";
m_map[204]= "No Content";
m_map[205]= "Reset Content";
m_map[206]= "Partial Content";
m_map[300]= "Multiple Choices";
m_map[301]= "Moved Permanently";
m_map[302]= "Found";
m_map[303]= "See Other";
m_map[304]= "Not Modified";
m_map[305]= "Use Proxy";
m_map[307]= "Temporary Redirect";
m_map[400]= "Bad Request";
m_map[401]= "Unauthorized";
m_map[402]= "Payment Required";
m_map[403]= "Forbidden";
m_map[404]= "Not Found";
m_map[405]= "Method Not Allowed";
m_map[406]= "Not Acceptable";
m_map[407]= "Proxy Authentication Required";
m_map[408]= "Request Time-out";
m_map[409]= "Conflict";
m_map[410]= "Gone ";
m_map[411]= "Length Required";
m_map[412]= "Precondition Failed";
m_map[413]= "Request Entity Too Large";
m_map[414]= "Request-URI Too Large";
m_map[415]= "Unsupported Media Type";
m_map[416]= "Requested range not satisfiabl";
m_map[417]= "Expectation Failed";
m_map[500]= "Internal Server Error";
m_map[501]= "Not Implemented";
m_map[502]= "Bad Gateway";
m_map[503]= "Service Unavailable";
m_map[504]= "Gateway Time-out";
m_map[505]= "HTTP Version not supported";
}
CHttpClient::~CHttpClient()
{
}
bool CHttpClient::Reset()
{
m_noCancel=true;
m_hParent=NULL;
m_Message=0;
memset(m_buffer,0,BUFFER_SIZE);
memset(m_heads_buffer,0,HEADS_BUFFER_SIZE);
return 1;
}
//HTTP下载主程序
bool CHttpClient::Download(char *url, HWND hParent,long msg)
{
m_Message=m_Message;
m_hParent=hParent;
//状态为忙
Reset();
char hostname[256];
memset(hostname,0,256);
GetHostName(url,hostname);
long AllSize=0;
long ReadSize=0;
bool headFinished=false;
int s;
s=tcp.connect(hostname,80,TCP_TIMEOUT,1);
if(s<0)
return false;
sprintf(m_buffer,"GET %s HTTP/1.0 \r\nHost:%s\r\nAccept:*/*\r\nUser-Agent: AutoUpdate/1.0 \r\n\r\n",url,hostname);
tcp.send(s,m_buffer,strlen(m_buffer),TCP_TIMEOUT);
//先取PEEK_SIZE个字节,这样可以确保取到Content-Length
ReadSize=tcp.recv(s,m_buffer,PEEK_SIZE,TCP_TIMEOUT);
if(ReadSize==-1)
return false;
m_buffer[ReadSize]=0;
memset(hostname,0,256);
int m,n;
m=Instr(m_buffer," ");
n=Instr(m_buffer+m+1," ");
memcpy(hostname,m_buffer+m+1,n);
m_status=atoi(hostname);
if(m_status!=200)return false;
memset(hostname,0,256);
if(GetHeader(m_buffer,"Content-Length",hostname)<0)
return false;
//取得内容总长度
AllSize=atol(hostname);
memset(hostname,0,256);
//寻找HTTP数据区表示
int i;
i=Instr(m_buffer,"\r\n\r\n");
if(i>0)
{
memcpy(m_heads_buffer,m_buffer,i+4);
headFinished=true;
ReadSize=ReadSize-i-4;
OnDataRecived(m_buffer+i+4,ReadSize,true);
}
while(ReadSize<AllSize && m_noCancel)
{
int nSize;
if(headFinished)
{
nSize=(AllSize-ReadSize)>BUFFER_SIZE?BUFFER_SIZE:(AllSize-ReadSize);
memset(m_buffer,0,BUFFER_SIZE);
if(tcp.recv(s,m_buffer,nSize,TCP_TIMEOUT)!=nSize)
return false;
ReadSize+=nSize;
m_buffer[nSize]=0;
OnDataRecived(m_buffer,nSize);
}
else
{
nSize=(AllSize-ReadSize)>(BUFFER_SIZE-ReadSize)?(BUFFER_SIZE-ReadSize):(AllSize-ReadSize);
if(tcp.recv(s,m_buffer+ReadSize,nSize,TCP_TIMEOUT)!=nSize)
return false;
ReadSize+=nSize;
m_buffer[nSize]=0;
//寻找HTTP数据区表示
i=Instr(m_buffer,"\r\n\r\n");
if(i>0)
{
memcpy(m_heads_buffer,m_buffer,i+4);
headFinished=true;
ReadSize=ReadSize-i-4;
OnDataRecived(m_buffer+i+4,ReadSize,true);
}
}
}
if(!m_noCancel)remove(m_fname);
tcp.close(s);
return true;
}
int CHttpClient::GetStatus()
{
return m_status;
}
//从URL中取出主机名
long CHttpClient::GetHostName(char *url, char *buf)
{
int i,j;
char* lpsz = _tcsstr(url, "//");
if(!lpsz)return -1;
i=lpsz-url+2;
lpsz= _tcsstr(url+i, "/");
if(!lpsz)return -1;
j=lpsz-url;
memcpy(buf,url+i,j-i);
return j-i;
}
long CHttpClient::GetHeader(char *headname, char *buf)
{
return GetHeader(m_heads_buffer,headname,buf);
}
long CHttpClient::GetHeader(char *from, char *headname, char *buf)
{
char *p;
char* lpsz = _tcsstr(from, headname);
if(!lpsz)return -1;
//lpsz++;
p=lpsz+strlen(headname)+2;
lpsz = _tcsstr(p, "\r\n");
if(!lpsz)return -1;
memcpy(buf,p,lpsz-p);
return strlen(buf);
}
void CHttpClient::OnDataRecived(char* data,long datasize ,int first)
{
if(m_hParent)
::SendMessage(m_hParent,m_Message,(unsigned int)data,datasize);
else
{
if(first)remove(m_fname);
FILE* f=fopen(m_fname,"ab");
if(f){
fwrite(data,1,datasize,f);
fclose(f);
}
}
//处理数据,一定要拷贝走哦,缓冲区可是循环使用的
}
inline long CHttpClient::Instr(char *from, char *find)
{
char* lpsz = _tcsstr(from, find);
return (!lpsz)?-1:lpsz-from;
}
bool CHttpClient::Download(char *url, char *fname)
{
strcpy(m_fname,fname);
return Download(url,NULL,NULL);
}
const char* CHttpClient::GetStatusString()
{
return m_map[m_status].c_str();
}
void CHttpClient::Cancel()
{
m_noCancel=false;
}
本文地址:http://com.8s8s.com/it/it26474.htm