用VC++6.0编写Proxy服务器 本人在用Oicq聊天时,经常收到一些好友发给我的用文本符号描绘的图像,觉得好羡慕啊,于是一想何我们一般常用的Internet代理服务器是用微软的Proxy Server 2.0 。但我们可以自己动手编写一个简单、小型的Proxy Server 。下面介绍具体的实现方法。
一. 原理 本程序的结构原理如下: 对于每一个用户的请求(Internet 请求,由浏览器发出),本程序将启动两个线程,一个把本地用户的请求数据发送到远程的Internet主机,另一个线程把远程主机的回应数据发送到本地请求用户。
二. 主要函数 UserToProxyThread ( void * pParam ) :它是用来把本地用户请求数据发送到远程主机的,起服务器线程角色。当接到本地(局域网)用户的请求,它就启动另一个自身线程,以侦听别的用户的请求,并读出已接收到的请求数据,接着启动第二个线程ProxyToServer()(这个线程用来连接远程主机),当远程主机连接成功后,它把已读出的本地用户请求数据发送到远程主机。 ProxyToServer ( void * pParam) ,可以被当作是客户端服务,它把远程主机发送来的数据分发给本地请求用户。
三. 开发运行环境 本程序是在VC++6.0环境下开发的,在Win95 和 WinNT4.0下运行正常。
四. 详细代码
#include "stdafx.h"#include <winsock2.h>#include <stdlib.h>#include <stdio.h>#include <string.h>#include <iostream>
using namespace std;
#define HTTP "http://"#define FTP "ftp://"#define PROXYPORT 5001#define BUFSIZE 10240
struct SocketPair{ SOCKET user_proxy; SOCKET proxy_server; bool IsUser_ProxyClosed; bool IsProxy_ServerClosec;};
struct ProxyParam{ char Address[256]; HANDLE User_SvrOK; SocketPair* pPair;
int Port;};
CWinApp theApp;SOCKET gListen_Socket;
UINT ProxyToServer(LPVOID pParam);UINT UserToProxyThread(void* pParam);
int StartServer(){ WSADATA wsaData; sockaddr_in local; SOCKET listen_socket;
if (::WSAStartup(0x202, &wsaData) != 0) { cout << "start up net work failed...." << endl;
exit(0); }
local.sin_addr.S_un.S_addr = INADDR_ANY; local.sin_family = AF_INET; local.sin_port = htons(PROXYPORT);
listen_socket = socket(AF_INET, SOCK_STREAM, 0);
if (listen_socket == INVALID_SOCKET) { cout << "create socket failed..." << endl;
return -1; }
if (bind(liste_socket, (sockaddr*)&local, sizeof(local)) != 0) { cout << "bind failed..." << endl;
return -1; }
if ((listen(listen_socket, 5)) != 0) { cout << "listen failed..." << endl;
return -1; }
gListen_Socket = listen_socket;
AfxBeginThread(UserToProxyThread, NULL);
return 1;}
int CloseServer(){ closesocket(gLiten_Socket);
WSACleanup();
return 1;}
//分析接收到的字符,得到远程主机地址int GetAddressAndPort(char* str, char* address, int* port){ char buf[BUFSIZE] = "/0"; char command[512] = "/0"; char proto[128] = "/0"; char* p = NULL;
int j = 0;
cout << "Please input command" << endl; cin >> command;
cout << "Please input buffer: " << endl; cin >> buf;
cout << "Please input proto: " << endl; cin >> proto;
p = strstr(buf, HTTP);
if (p) { p+=strlen(HTTP); for(int i=0;i< strlen(p);i++) { if( *(p+i)=='/') { break; } }
*(p+i)=0; strcpy(address,p); p=strstr(str,HTTP); for(int j=0;j< i+strlen(HTTP);j++) { *(p+j)=' '; //去掉远程主机名: GET http://www.njust.edu.cn/HTTP1.1 == > GET / HTTP1.1 } *port=80; //缺省的 http 端口 } else {//FTP, 不支持, 下面的代码可以省略. p=strstr(buf,FTP); if(!p) { return 0; }
p+=strlen(FTP); for(int i=0;i< strlen(p);i++) { if( *(p+i)=='/') { break; //Get The Remote Host } } *(p+i)=0; for(j=0;j< strlen(p);j++) { if(*(p+j)==':') { *port=atoi(p+j+1); //Get The Port *(p+j)=0; } else { *port=21; } } strcpy(address,p); p=strstr(str,FTP); for(j=0;j< i+strlen(FTP);j++) { *(p+j)=' '; } } return 1;
}
// 取到本地的数据,发往远程主机UINT UserToProxyThread(void *pParam){ char Buffer[BUFSIZE]; int Len; sockaddr_in from; SOCKET msg_socket; int fromlen,retval; SocketPair SPair; ProxyParam ProxyP; CWinThread *pChildThread; fromlen = sizeof(from); msg_socket = accept(gListen_Socket,(struct sockaddr*)&from,&fromlen);
AfxBeginThread(UserToProxyThread,pParam); //启动另一侦听. if( msg_socket == INVALID_SOCKET) { printf("/nError in accept "); return -5; }
//读客户的第一行数据 SPair.IsUser_ProxyClosed = FALSE; SPair.IsProxy_ServerClosed = TRUE; SPair.user_proxy = msg_socket;
retval = recv(SPair.user_proxy,Buffer,sizeof(Buffer),0); if(retval==SOCKET_ERROR) { printf("/nError Recv"); if(SPair.IsUser_ProxyClosed == FALSE) { closesocket(SPair.user_proxy); SPair.IsUser_ProxyClosed=TRUE; } } if (retval == 0) { printf("Client Close connection/n"); if (SPair.IsUser_ProxyClosed == FALSE) { closesocket(SPair.user_proxy); SPair.IsUser_ProxyClosed = TRUE; } } Len = retval;
#ifdef _DEBUG
Buffer[Len]=0; printf("/n Received %d bytes,data[%s]from client/n",retval,Buffer);#endif SPair.IsUser_ProxyClosed=FALSE; SPair.IsProxy_ServerClosed=TRUE; SPair.user_proxy=msg_socket; ProxyP.pPair=&SPair; ProxyP.User_SvrOK=CreateEvent(NULL,TRUE,FALSE,NULL); GetAddressAndPort( Buffer,ProxyP.Address,&ProxyP.Port); pChildThread=AfxBeginThread(ProxyToServer,(LPVOID)&ProxyP); ::WaitForSingleObject(ProxyP.User_SvrOK,60000); //等待联结 ::CloseHandle(ProxyP.User_SvrOK); while(SPair.IsProxy_ServerClosed ==FALSE && SPair.IsUser_ProxyClosed==FALSE) { retval=send(SPair.proxy_server,Buffer,Len,0); if(retval==SOCKET_ERROR) { printf("/n send() failed:error%d/n",WSAGetLastError()); if(SPair.IsProxy_ServerClosed==FALSE) { closesocket(SPair.proxy_server); SPair.IsProxy_ServerClosed=TRUE; } continue; } retval=recv(SPair.user_proxy,Buffer,sizeof(Buffer),0);
if(retval==SOCKET_ERROR) { printf("/nError Recv"); if(SPair.IsUser_ProxyClosed==FALSE) { closesocket(SPair.user_proxy); SPair.IsUser_ProxyClosed=TRUE; } continue; } if(retval==0) { printf("Client Close connection/n"); if(SPair.IsUser_ProxyClosed==FALSE) { closesocket(SPair.user_proxy); SPair.IsUser_ProxyClosed=TRUE; } break; } Len=retval;
#ifdef _DEBUG Buffer[Len]=0; printf("/n Received %d bytes,data[%s]from client/n",retval,Buffer);#endif } if(SPair.IsProxy_ServerClosed==FALSE) { closesocket(SPair.proxy_server); SPair.IsProxy_ServerClosed=TRUE; } if(SPair.IsUser_ProxyClosed==FALSE) { closesocket(SPair.user_proxy); SPair.IsUser_ProxyClosed=TRUE; } ::WaitForSingleObject(pChildThread- >m_hThread,20000); //Should check the return value }
// 读取远程主机数据,并发往本地客户机UINT ProxyToServer(LPVOID pParam){ ProxyParam * pPar=(ProxyParam*)pParam; char Buffer[BUFSIZE]; char *server_name= "localhost"; unsigned short port ; int retval,Len; unsigned int addr; int socket_type ; struct sockaddr_in server; struct hostent *hp; SOCKET conn_socket; socket_type = SOCK_STREAM; server_name = pPar- >Address; port = pPar- >Port;
if (isalpha(server_name[0])) { /* server address is a name */ hp = gethostbyname(server_name); } else { /* Convert nnn.nnn address to a usable one */ addr = inet_addr(server_name); hp = gethostbyaddr((char *)&addr,4,AF_INET); }
if (hp == NULL ) { fprintf(stderr,"Client: Cannot resolve address [%s]: Error %d/n", server_name,WSAGetLastError()); ::SetEvent(pPar- >User_SvrOK); return 0; } // Copy the resolved information into the sockaddr_in structure
memset(&server,0,sizeof(server)); memcpy(&(server.sin_addr),hp- >h_addr,hp- >h_length); server.sin_family = hp- >h_addrtype; server.sin_port = htons(port); conn_socket = socket(AF_INET,socket_type,0); /* 打开一个 socket */ if (conn_socket < 0 ) { fprintf(stderr,"Client: Error Opening socket: Error %d/n",WSAGetLastError()); pPar- >pPair- >IsProxy_ServerClosed=TRUE; ::SetEvent(pPar- >User_SvrOK); return -1; }
#ifdef _DEBUG printf("Client connecting to: %s/n",hp- >h_name);#endif if (connect(conn_socket,(struct sockaddr*)&server,sizeof(server))== SOCKET_ERROR) { fprintf(stderr,"connect() failed: %d/n",WSAGetLastError()); pPar->pPair->IsProxy_ServerClosed = TRUE; ::SetEvent(pPar- >User_SvrOK); return -1; } pPar- >pPair- >proxy_server=conn_socket; pPar- >pPair- >IsProxy_ServerClosed=FALSE; ::SetEvent(pPar- >User_SvrOK); // cook up a string to send while(!pPar- >pPair- >IsProxy_ServerClosed &&!pPar- >pPair->IsUser_ProxyClosed) { retval = recv(conn_socket,Buffer,sizeof (Buffer),0 ); if (retval == SOCKET_ERROR ) { fprintf(stderr,"recv() failed: error %d/n",WSAGetLastError()); closesocket(conn_socket); pPar->pPair->IsProxy_ServerClosed = TRUE; break; } Len=retval; if (retval == 0) { printf("Server closed connection/n"); closesocket(conn_socket); pPar->pPair->IsProxy_ServerClosed=TRUE; break; } retval = send(pPar- >pPair- >user_proxy,Buffer,Len,0); if (retval == SOCKET_ERROR) { fprintf(stderr,"send() failed: error %d/n",WSAGetLastError()); closesocket(pPar- >pPair- >user_proxy); pPar->pPair->IsUser_ProxyClosed=TRUE; break; }
#ifdef _DEBUG Buffer[Len]=0; printf("Received %d bytes, data [%s] from server/n",retval,Buffer);#endif } if(pPar- >pPair- >IsProxy_ServerClosed==FALSE) { closesocket(pPar- >pPair- >proxy_server); pPar->pPair- >IsProxy_ServerClosed=TRUE; } if(pPar- >pPair- >IsUser_ProxyClosed==FALSE) { closesocket(pPar- >pPair- >user_proxy); pPar- >pPair- >IsUser_ProxyClosed=TRUE; } return 1;} int _tmain(int argc, TCHAR* argv[], TCHAR* envp[]){ int nRetCode = 0; // 初始化SOCKET if (!AfxWinInit(::GetModuleHandle(NULL), NULL, ::GetCommandLine(), 0)) { // 错误处理 cerr < < _T("Fatal Error: MFC initialization failed") < < endl; nRetCode = 1; } else { // 主程序开始. StartServer(); } while(1) { if(getchar()=='q') { break; } }
CloseServer();
return nRetCode;}