今日是:
  小新技术网 -=> 程序开发 -=> C/C++区 -=> 正文

用VC++实现http代理

作者:[本站整理] 来源:[本站] 浏览:[] 评论:[]  【字体:
为了帮网友些个用http下载动画的程序,临时在网上翻了翻,看看有没有利用http代理来下载的例子。结果,似乎很多人都愿意去转载一个有头无尾的例子,还美其名曰“我在查阅RFC文档和相关资料后,特总结一些TCP协议穿透代理服务器的程序片断,希望对大家有所帮助。”

  如果真的想帮助大家,为什么不说的详细一些?

  无奈之下,自己去翻rfc文档,找了些资料,写了这个利用http代理来下载文件的资料

  代码如下:

  (1)一些基本变量

SOCKET HTTPSocket; // 主socket
struct sockaddr_in SocketAddr; // address socket
struct sockaddr_in BindSocket; // for bind


int m_nRecvTimeout; // recieve timeout
int m_nSendTimeout; // send timeout

WSADATA wsaData;

// 要下载文件部分。好像在BindSocket.sin_addr.s_addr = inet_addr (strHost);时,只能使用ip地址,所以了。。。

// 如果谁知道更好的方法,别忘了告诉我一下。

CString strHost="111.111.111.111 ";
CString DownLoadAddress="http://www.aitenshi.com/bbs/images/";
CString hostFile="logo.gif";
int HttpPort=80;



  (2)一些函数,用来取得http头,和获取文件大小

int GetFileLength(char *httpHeader)
{
CString strHeader;
int local;
strHeader=(CString)httpHeader;
local=strHeader.Find("Content-Length",0);
local+=16;
strHeader.Delete(0,local);
local=strHeader.Find("\r");
strHeader.SetAt(local,'\0');

char temp[30];
strcpy(temp,strHeader.GetBuffer(strHeader.GetLength()));
return atoi(temp);
}

int GetHttpHeader(SOCKET sckDest,char *str)
{
BOOL m_bResponsed=0;
int m_nResponseHeaderSize;

if(!m_bResponsed)
{
char c = 0;
int nIndex = 0;
BOOL bEndResponse = FALSE;
while(!bEndResponse && nIndex < 1024)
{
recv(sckDest,&c,1,0);
str[nIndex++] = c;
if(nIndex >= 4)
{
if(str[nIndex - 4] == '\r' && str[nIndex - 3] == '\n'
&& str[nIndex - 2] == '\r' && str[nIndex - 1] == '\n')
bEndResponse = TRUE;
}
}
m_nResponseHeaderSize = nIndex;
m_bResponsed = TRUE;
}

return m_nResponseHeaderSize;

}


  (3)用来发送的部分

void szcopy(char* dest,const char* src,int nMaxBytes)
{
int i_cntr=0;
while ((src[i_cntr]!='\0')    (i_cntr dest[i_cntr]=src[i_cntr++];
dest[i_cntr]='\0';
}

BOOL SocketSend(SOCKET sckDest,const char* szHttp)
{

char szSendHeader[MAXHEADERLENGTH];
int iLen=strlen(szHttp);
szcopy(szSendHeader,szHttp,iLen);
if(send (sckDest ,(const char FAR *)szSendHeader ,iLen ,0)==SOCKET_ERROR)
{
closesocket(sckDest);
AfxMessageBox("Error when send");
return FALSE;
}

return TRUE;
}

BOOL SocketSend(SOCKET sckDest,CString szHttp)
{

int iLen=szHttp.GetLength();
if(send (sckDest,szHttp,iLen,0)==SOCKET_ERROR)
{
closesocket(sckDest);
AfxMessageBox("Error when send");
return FALSE;
}

return TRUE;
}


  (4)用于连接的函数

  这里是做了一些连接用的操作,分了两种情况

  1)如果没有使用代理,则直接连到你指定的计算机

  2)如果使用了代理,则直接连到代理

BOOL CDLAngelDlg::ConnectHttp()
{

message="正在建立连接\n";


UpdateData(TRUE);
if(m_combo=="HTTP") // m_combo 一个下拉条
{
HTTPSocket=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
SocketAddr.sin_addr.s_addr = inet_addr (m_ProxyAddr);
SocketAddr.sin_family=AF_INET;
SocketAddr.sin_port=htons(atoi(m_Port));

struct fd_set fdSet;
struct timeval tmvTimeout={0L,0L};

FD_ZERO(&fdSet);
FD_SET(HTTPSocket, &fdSet);

if (select(0,&fdSet,NULL,NULL,&tmvTimeout)==SOCKET_ERROR)
{
closesocket(HTTPSocket);
AfxMessageBox("Error when select.");
return 0;
}


if (connect(HTTPSocket, (const struct sockaddr *)&SocketAddr, sizeof(SocketAddr))==SOCKET_ERROR)
{
message="\n代理连接失败\n";
m_message.CleanText();
m_message.AddText(message);
return 0;
}


// 发送CONNCET请求令到代理服务器,用于和代理建立连接

//代理服务器的地址和端口放在m_ProxyAddr,m_Port 里面

CString temp;
char tmpBuffer[1024];
temp.Format("CONNECT %s:%s HTTP/1.1\r\nUser-Agent: MyApp/0.1\r\n\r\n",m_ProxyAddr,m_Port);
if(!SocketSend(HTTPSocket,temp))
{
message="连接代理失败";
return 0;
}

// 取得代理响应,如果连接代理成功,代理服务器将返回200 Connection established

GetHttpHeader(HTTPSocket,tmpBuffer);
temp=tmpBuffer;
if(temp.Find("HTTP/1.0 200 Connection established",0)==-1)
{
message="连接代理失败\n";
return 0;
}

message="代理连接完成\n";
m_message.AddText("代理连接完成\n");
return 1; // ----------〉这里是应该注意的,连接到代理后,就可以返回了,不需要再连接网上的另外一台机,代理服务器会自动转发数据,所以,连接完代理就像连接到网上另外一台机一样
}

// 这个,是为了给其他代理做准备
else if(m_combo=="Socks4")
{MessageBox("请注意,现在无法使用代理功能!");}
else if(m_combo=="Socks5")
{MessageBox("请注意,现在无法使用代理功能!");}


// 如果没有使用代理,就要连接到网上的另一台机

// 准备socket
HTTPSocket=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);

if (HTTPSocket==INVALID_SOCKET)
{
AfxMessageBox("Error when socket");
return 0;
}

//设置超时
struct linger zeroLinger;
zeroLinger.l_onoff = 1;
zeroLinger.l_linger = 0;
if(setsockopt(HTTPSocket,SOL_SOCKET,SO_LINGER
,(const char *)&zeroLinger
,sizeof(zeroLinger))!=0)
{
closesocket(HTTPSocket);
AfxMessageBox("Error when setscokopt(LINGER)");
return 0;
}
//设置接收超时
if(setsockopt(HTTPSocket,SOL_SOCKET,SO_RCVTIMEO
,(const char *)&m_nRecvTimeout
,sizeof(m_nRecvTimeout))!=0)
{
closesocket(HTTPSocket);
AfxMessageBox("Error when setsockopt(RCVTIME).");
return 0;
}

//设置发送超时
if(setsockopt(HTTPSocket,SOL_SOCKET,SO_SNDTIMEO
,(const char *)&m_nSendTimeout
,sizeof(m_nSendTimeout))!=0)
{
closesocket(HTTPSocket);
AfxMessageBox("Error when setsockopt(SNDTIMEO).");
return 0;
}


SocketAddr.sin_addr.s_addr = htonl (INADDR_ANY);
SocketAddr.sin_family=AF_INET;

// 进行端口绑定
if (bind (HTTPSocket,
(const struct sockaddr FAR *)&SocketAddr,
sizeof(SocketAddr))==SOCKET_ERROR)
{
closesocket(HTTPSocket);
AfxMessageBox("Error when bind socket.");
return 0;
}

//准备连接

/// 准备连接信息
BindSocket.sin_addr.s_addr = inet_addr (strHost);
BindSocket.sin_family=AF_INET;
BindSocket.sin_port=htons(HttpPort);


struct fd_set fdSet;
struct timeval tmvTimeout={0L,0L};

FD_ZERO(&fdSet);
FD_SET(HTTPSocket, &fdSet);

if (select(0,&fdSet,NULL,NULL,&tmvTimeout)==SOCKET_ERROR)
{
closesocket(HTTPSocket);
AfxMessageBox("Error when select.");
return 0;
}

// 连接


if (connect(HTTPSocket, (const struct sockaddr *)&BindSocket, sizeof(BindSocket))==SOCKET_ERROR)
{
AfxMessageBox("第一次连接失败,准备第二次连接");
if (connect(HTTPSocket
,(const struct sockaddr *)&BindSocket
,sizeof(BindSocket))==SOCKET_ERROR)
{
closesocket(HTTPSocket);
AfxMessageBox("连接失败");
return 0;
}

}

message="连接完成\n";

return 1;
}


  (5)发送http请求,为下载数据进行准备

int CDLAngelDlg::SendHttpHeader()
{
//进行下载

CString temp;
BOOL bReturn;
char tmpBuffer[MAXBLOCKSIZE];


///第1行:方法,请求的路径,版本
temp="GET "+DownLoadAddress+hostFile+" HTTP/1.0\r\n";
bReturn=SocketSend(HTTPSocket,temp);
if(!bReturn)
{
message="发送请求失败";
return 0;
}


///第2行:主机
temp="Host "+strHost+"\r\n";
bReturn=SocketSend(HTTPSocket,temp);
if(!bReturn)
{
message="发送请求失败";
return 0;
}


///第3行:接收的数据类型
bReturn=SocketSend(HTTPSocket,"Accept: */*\r\n");
if(!bReturn)
{
message="发送请求失败";
return 0;
}


///第4行:
temp=DownLoadAddress;
temp.Insert(0,"Referer ");
temp+="\r\n";
bReturn=SocketSend(HTTPSocket,temp);
if(!bReturn)
{
message="发送请求失败";
return 0;
}


///第5行:浏览器类型

bReturn=SocketSend(HTTPSocket,"User-Agent: Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt; DTS Agent;)\r\n");
if(!bReturn)
{
message="发送请求失败";
return 0;
}

///第6行:连接设置,保持
// SocketSend(HTTPSocket,"Connection:Keep-Alive\r\n");

///第7行:Cookie.

bReturn=SocketSend(HTTPSocket,"Cache-Control: no-cache\r\n");
if(!bReturn)
{
message="发送请求失败";
return 0;
}


bReturn=SocketSend(HTTPSocket,"Proxy-Connection: Keep-Alive\r\n");
if(!bReturn)
{
message="发送请求失败";
return 0;
}

/// 续传

Range是要下载的数据范围,对续传很重要
if(continueFlag)
{
temp.Format("Range: bytes=%d- \r\n",conLength);
bReturn=SocketSend(HTTPSocket,temp);
if(!bReturn)
{
message="发送请求失败";
return 0;
}
}


///最后一行:空行
bReturn=SocketSend(HTTPSocket,"\r\n");
if(!bReturn)
{
message="发送请求失败";
return 0;
}

///取得http头
int i;
i=GetHttpHeader(HTTPSocket,tmpBuffer);
if(!i)
{
message="获取HTTP头出错";
return 0;
}

//如果取得的http头含有404等字样,则表示连接出问题
temp=tmpBuffer;
if(temp.Find("404")!=-1)
{

return 0;
}

// 得到待下载文件的大小

filelength=GetFileLength(tmpBuffer);

return 1;
}


  这样,就连接到网上的另一台机了,如何下载数据,不用多说了吧

while((num!=SOCKET_ERROR) && (num!=0))
{
num=recv (HTTPSocket
,(char FAR *)tmpBuffer
,(MAXBLOCKSIZE-1)
,0);


file.Write(tmpBuffer,num);

if(ExitFlag)
{
file.Close();
closesocket(HTTPSocket);

DownComplete=1;

m_message.CleanText();
m_message.ShowColorText(RGB(128,128,0),DLCompleteMes);

m_progress.ShowWindow(SW_HIDE);
m_stopDownload.ShowWindow(SW_HIDE);
_endthread();
}

}


  基本就是这样了,本人写程序水平也不是很高,这个程序还是可以用的。
下一篇:只要有可能就推迟变量定义
上一篇:C++/CLI思辨录之传递托管堆地址
IP查询、IP签名
打印 】【 收藏 】【 评论 】【 推荐
相关文章 栏目推荐文章 栏目热门文章
 推荐文章 C# 3.0语言详解之基本的语言增强 .. 
 推荐文章 C++程序设计最佳实践 
 推荐文章 C语言嵌入式系统编程之屏幕操作 
 推荐文章 QQ用户小心!C语言实现QQ密码大盗.. 
 推荐文章 C语言初学者入门讲座 第一讲 慨述.. 
 推荐文章 用C++实现简单的文件I/O操作 
 推荐文章 C++的iostream标准库介绍以及对左.. 
 推荐文章 用C++访问SQL Server 2000 
 普通文章 伪随机数生成及在VC++中的实现 
 推荐文章 TurboC程序设计初步  
 推荐文章 QQ用户小心!C语言实现QQ密码大盗.. 
 普通文章 C语言程序设计基础之联合 
 普通文章 学C++不得不看的一篇文章 
 推荐文章 强大的语言——C入门  
 推荐文章 C# 3.0语言详解之基本的语言增强 .. 
 推荐文章 用C++实现简单的文件I/O操作 
最新文章 最新推荐文章 热门文章
 普通文章 简历封面 
 普通文章 简历封皮(二) 
 推荐文章 用好Windows共享 确保安全 
 推荐文章 多点出发:消除局域网遗留共享痕迹.. 
 普通文章 只需三步!闪盘立刻变成启动盘 
 普通文章 战无不胜 一目了然看穿局域网 
 普通文章 Win 2000/XP在局域网内批量升级 
 普通文章 黑客经常更改的系统配置文件及注册.. 
 推荐文章 用好Windows共享 确保安全 
 推荐文章 多点出发:消除局域网遗留共享痕迹.. 
 推荐文章 Ghost二十个鲜为人知的实用参数 
 推荐文章 ASP.NET程序中常用的三十三种代码.. 
 推荐文章 黑客利用Ms05002溢出找“肉鸡” 
 推荐文章 C# 3.0语言详解之基本的语言增强 .. 
 推荐文章 Ghost所有运行错误代码完全大揭秘.. 
 推荐文章 利用Java Swing 实现游戏开发 
 推荐文章 秘籍:QQ头像任意换 
 普通文章 提升QQ等级 QQ挂机升级外挂  
 普通文章 QQ100个经典个性签名!可爱经典贴图.. 
 推荐文章 BIOS设置图解教程(多图) 
 普通文章 惊现腾讯QQ刷等级漏洞 
 普通文章 求职简历封皮  
 普通文章 突破在线观看电影 
 普通文章 GIF动画图片制作教程 
点击查看更多评论
笔名:
评论:
[评论将在5分钟内被审核,请耐心等待]
【注】 发表评论必需遵守以下条例:
  • 尊重网上道德,遵守中华人民共和国的各项有关法律法规
  • 承担一切因您的行为而直接或间接导致的民事或刑事法律责任
  • 本站管理人员有权保留或删除其管辖留言中的任意内容
  • 本站有权在网站内转载或引用您的评论
  • 参与本评论即表明您已经阅读并接受上述条款
  • 本站大部分为网络转载,如有版权问题,请通知我们,我们立即更正!

设置首页 - 版权声明 - 广告服务 - 关于我们 - 联系我们 - 友情连接
Copyright ©2003-2005 xker.com All rights reserved. 网站合作、广告联系QQ:12231446
小新技术网  冀ICP备05002857号