VC++實現HTTP代理
分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow
也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!
HTTP代理:www對於每一個上網的人都再熟悉不過了,www連線請求就是採用的http協議,所以我們在瀏覽網頁,下載資料(也可採用ftp協議)時就是用http代理。它通常繫結在代理伺服器的80、3128、8080等埠上
代理伺服器英文全稱是Proxy Server,其功能就是代理網路使用者去取得網路資訊。形象的說:它是網路資訊的中轉站。在一般情況下,我們使用網路瀏覽器直接去連線其他Internet站點取得網路資訊時,須送出Request訊號來得到回答,然後對方再把資訊以bit方式傳送回來。
代理伺服器是介於瀏覽器和Web伺服器之間的一臺伺服器,有了它之後,瀏覽器不是直接到Web伺服器去取回網頁而是向代理伺服器發出請求,Request訊號會先送到代理伺服器,由代理伺服器來取回瀏覽器所需要的資訊並傳送給你的瀏覽器。而且,大部分代理伺服器都具有緩衝的功能,就好象一個大的Cache,它有很大的儲存空間,它不斷將新取得資料儲存到它本機的儲存器上,如果瀏覽器所請求的資料在它本機的儲存器上已經存在而且是最新的,那麼它就不重新從Web伺服器取資料,而直接將儲存器上的資料傳送給使用者的瀏覽器,這樣就能顯著提高瀏覽速度和效率。
更重要的是:Proxy Server(代理伺服器)是Internet鏈路級閘道器所提供的一種重要的安全功能,它的工作主要在開放系統互聯(OSI)模型的對話層。
主要的功能有:
1.突破自身IP訪問限制,訪問國外站點。如:教育網、169網等網路使用者可以通過代理訪問國外網站。
2.訪問一些單位或團體內部資源,如某大學FTP(前提是該代理地址在該資源的允許訪問範圍之內),使用教育網內地址段免費
代理伺服器,就可以用於對教育 網開放的各類FTP下載上傳,以及各類資料查詢共享等服務。
3.突破中國電信的IP封鎖:中國電信使用者有很多網站是被限制訪問的,這種限制是人為的,不同Serve對地址的封鎖是不同的。所以不能訪問時可以換一個國 外的代理伺服器試試。
4.提高訪問速度:通常代理伺服器都設定一個較大的硬碟緩衝區,當有外界的資訊通過時,同時也將其儲存到緩衝區中,當其他使用者再訪問相同的資訊時, 則直接由緩衝區中取出資訊,傳給使用者,以提高訪問速度。
5.隱藏真實IP:上網者也可以通過這種方法隱藏自己的IP,免受攻擊。
下面我們來實現HTTP代理
#include <stdio.h> #include <winsock2.h> #define MAXBUFLEN 20480 #define HTTPADDLEN 50 #define TIMEWAIT 2000 #pragma comment(lib,"ws2_32.lib")SOCKET Global[1000]; DWORD WINAPI Proxy( LPVOID pSocket); int ParseHttpRequest (char * SourceBuf,int DataLen,void * ServerAddr); int main(int argc,char * argv[]) { SOCKET MainSocket,ClientSocket; struct sockaddr_in Host,Client; WSADATA WsaData; int AddLen,i; //初始化 if(WSAStartup(MAKEWORD(2 ,2),&WsaData) < 0) { printf("初始化失敗\n"); return 1; } //建立socket埠 MainSocket = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP); if(MainSocket == SOCKET_ERROR) { printf("埠建立錯誤\n"); return 1; } Host.sin_family = AF_INET; Host.sin_port = htons(8080); Host.sin_addr.s_addr = inet_addr("127.0.0.1"); printf("正在工作\n"); //繫結socket if(bind(MainSocket,(SOCKADDR *)&Host,sizeof(Host)) != 0) { printf("繫結錯誤\n"); } i = 0; //監聽 if(listen(MainSocket,5) == SOCKET_ERROR) { printf("監聽錯誤\n"); } AddLen = sizeof(Client); //連線新的客戶 i = 0; for(;;) { ClientSocket = accept(MainSocket,(SOCKADDR *)&Client,&AddLen); if(ClientSocket == SOCKET_ERROR) { printf("接受客戶請求錯誤!\n"); } printf("."); i ++ ; if( i >= 1000) i = 0; Global[i] = ClientSocket; //對於每一個客戶啟動不同的執行緒程進行控制 //這個地方在使用ClientSocket的時候,要不要保證在某一時刻內只能有一個程序使用? CreateThread(NULL,0,Proxy,(LPVOID)Global[i],0,NULL); } return 0;} DWORD WINAPI Proxy( LPVOID pSocket) { SOCKET ClientSocket; char ReceiveBuf[MAXBUFLEN]; int DataLen; struct sockaddr_in ServerAddr; SOCKET ProxySocket; int i = 0; int time = TIMEWAIT; //得到引數中的埠號資訊 ClientSocket = (SOCKET)pSocket; //接受第一次請求資訊 memset(ReceiveBuf,0,MAXBUFLEN); DataLen = recv(ClientSocket,ReceiveBuf,MAXBUFLEN,0); if(DataLen == SOCKET_ERROR) { printf("錯誤\n"); closesocket(ClientSocket); return 0; } if(DataLen == 0) { closesocket(ClientSocket); return 0; } //處理請求資訊,分離出伺服器地址 if( ParseHttpRequest(ReceiveBuf,DataLen,(void *)&ServerAddr) < 0) { closesocket(ClientSocket); goto error; } //建立新的socket用來和伺服器進行連線 ProxySocket = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP); //設定超時時間 setsockopt(ProxySocket,SOL_SOCKET,SO_RCVTIMEO,(char *)&time,sizeof(time)); if(ProxySocket == SOCKET_ERROR) { printf("埠建立錯誤\n"); return 0; } if(connect(ProxySocket,(SOCKADDR *)&ServerAddr,sizeof(ServerAddr)) == SOCKET_ERROR) { //printf("連線伺服器錯誤"); goto error; } //開始進行資料傳輸處理 //傳送到伺服器端 if(send(ProxySocket,ReceiveBuf,DataLen,0) == SOCKET_ERROR) { //printf("資料傳送錯誤"); goto error; } //從伺服器端接受資料 while(DataLen > 0) { memset(ReceiveBuf,0,MAXBUFLEN); if((DataLen = recv(ProxySocket,ReceiveBuf,MAXBUFLEN,0)) <= 0) { // printf("資料接受錯誤"); break; } else //傳送到客戶端 if(send(ClientSocket,ReceiveBuf,DataLen,0) < 0) { // printf("資料傳送錯誤"); break; } } error: closesocket(ClientSocket); closesocket(ProxySocket); return 0; } int ParseHttpRequest(char * SourceBuf,int DataLen,void * ServerAddr) { char * HttpHead = "http://"; char * FirstLocation = NULL; char * LastLocation = NULL; char * PortLocation = NULL; char ServerName[HTTPADDLEN]; char PortString[10]; int NameLen; struct hostent * pHost; struct sockaddr_in * pServer = (struct sockaddr_in *)ServerAddr; //取得http://的位置 FirstLocation = strstr(SourceBuf,HttpHead) + strlen(HttpHead); //取得/的位置 printf("%s\n",FirstLocation); LastLocation=strstr(FirstLocation,"/"); //得到http://和/之間的伺服器的名稱 memset(ServerName,0,HTTPADDLEN); memcpy(ServerName,FirstLocation,LastLocation - FirstLocation); //有些情況下,請求的地址中帶有埠號格式為“:+ 埠號”; //取得 :的位置 PortLocation = strstr(ServerName,":"); //填充server結構 pServer->sin_family = AF_INET; //在url中制定了伺服器埠 if(PortLocation != NULL) { NameLen = PortLocation - ServerName -1; memset(PortString,0,10); memcpy(PortString,PortLocation + 1,NameLen); pServer->sin_port = htons((u_short)atoi(PortString)); *PortLocation = 0; } else//在url中,沒有制定伺服器埠 { pServer->sin_port=htons(80); } if(NameLen > HTTPADDLEN) { printf("伺服器名字太長\n"); return -1; } //得到伺服器資訊 //如果地址資訊是以IP地址(192.168.0.1)的形式出現的 if(ServerName[0] >= '0' && ServerName[0] <= '9') { pServer->sin_addr.s_addr = inet_addr(ServerName); } //以域名的形式出現的(www.sina.com.cn) else { pHost = (struct hostent *)gethostbyname(ServerName); if(!pHost) { printf("取得主機資訊錯誤\n"); printf("%s\n",ServerName); return -1; } memcpy(&pServer->sin_addr,pHost->h_addr_list[0],sizeof(pServer->sin_addr)); } return 0; }