为了帮网友些个用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<nMaxBytes)) 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(); }
}
基本就是这样了,本人写程序水平也不是很高,这个程序还是可以用的。
|