随笔 - 150  文章 - 230  trackbacks - 0
<2008年9月>
31123456
78910111213
14151617181920
21222324252627
2829301234
567891011

常用链接

留言簿(9)

随笔分类

随笔档案

文章档案

相册

收藏夹

搜索

  •  

最新评论

阅读排行榜

评论排行榜

/*************************************  
    *   一个基础的代理服务器类  
    *************************************  
    */  
  import   java.net.*;  
  import   java.io.*;  
   
  public   class   HttpProxy   extends   Thread   {  
          static   public   int   CONNECT_RETRIES=5;  
          static   public   int   CONNECT_PAUSE=5;  
          static   public   int   TIMEOUT=50;  
          static   public   int   BUFSIZ=1024;  
          static   public   boolean   logging   =   false;  
          static   public   OutputStream   log=null;  
          //   传入数据用的Socket  
          protected   Socket   socket;  
          //   上级代理服务器,可选  
          static   private   String   parent=null;  
          static   private   int   parentPort=-1;  
          static   public   void   setParentProxy(String   name,   int   pport)   {  
  parent=name;  
  parentPort=pport;  
          }  
   
          //   在给定Socket上创建一个代理线程。  
          public   HttpProxy(Socket   s)   {   socket=s;   start();   }  
   
          public   void   writeLog(int   c,   boolean   browser)   throws   IOException   {  
  log.write(c);  
          }  
   
          public   void   writeLog(byte[]   bytes,int   offset,   int   len,   boolean   browser)   throws   IOException   {  
  for   (int   i=0;i<len;i++)   writeLog((int)bytes[offset+i],browser);  
          }  
   
   
          //   默认情况下,日志信息输出到  
          //   标准输出设备  
          //   派生类可以覆盖它  
          public   String   processHostName(String   url,   String   host,   int   port,   Socket   sock)   {  
  java.text.DateFormat   cal=java.text.DateFormat.getDateTimeInstance();  
  System.out.println(cal.format(new   java.util.Date())   +   "   -   "   +   url   +   "   "    
                              +   sock.getInetAddress()+"\n");  
  return   host;  
          }  
   
   
   
          //   执行操作的线程  
          public   void   run()   {  
  String   line;  
  String   host;  
  int   port=80;  
                  Socket   outbound=null;  
  try   {  
          socket.setSoTimeout(TIMEOUT);  
          InputStream   is=socket.getInputStream();  
          OutputStream   os=null;  
          try   {  
                                  //   获取请求行的内容  
  line="";  
  host="";  
  int   state=0;  
  boolean   space;  
  while   (true)   {  
          int   c=is.read();  
          if   (c==-1)   break;  
          if   (logging)   writeLog(c,true);  
          space=Character.isWhitespace((char)c);    
          switch   (state)   {  
          case   0:  
  if   (space)   continue;    
                  state=1;  
          case   1:  
  if   (space)   {  
          state=2;  
          continue;  
  }  
  line=line+(char)c;  
  break;  
          case   2:  
  if   (space)   continue;   //   跳过多个空白字符  
                      state=3;  
          case   3:  
  if   (space)   {  
          state=4;    
                                                          //   只取出主机名称部分  
          String   host0=host;  
          int   n;  
          n=host.indexOf("//");  
          if   (n!=-1)   host=host.substring(n+2);  
          n=host.indexOf('/');  
          if   (n!=-1)   host=host.substring(0,n);  
                                                          //   分析可能存在的端口号  
          n=host.indexOf(":");  
          if   (n!=-1)   {    
  port=Integer.parseInt(host.substring(n+1));  
  host=host.substring(0,n);  
          }  
          host=processHostName(host0,host,port,socket);  
          if   (parent!=null)   {  
  host=parent;  
  port=parentPort;  
          }  
          int   retry=CONNECT_RETRIES;  
          while   (retry--!=0)   {  
  try   {  
          outbound=new   Socket(host,port);  
          break;  
  }   catch   (Exception   e)   {   }  
                                                                  //   等待  
  Thread.sleep(CONNECT_PAUSE);  
          }  
          if   (outbound==null)   break;  
          outbound.setSoTimeout(TIMEOUT);  
          os=outbound.getOutputStream();  
          os.write(line.getBytes());  
          os.write('   ');  
          os.write(host0.getBytes());  
          os.write('   ');  
          pipe(is,outbound.getInputStream(),os,socket.getOutputStream());  
          break;  
  }  
  host=host+(char)c;  
  break;  
          }  
  }  
          }  
          catch   (IOException   e)   {   }  
   
          }   catch   (Exception   e)   {   }  
          finally   {  
          try   {   socket.close();}   catch   (Exception   e1)   {}  
          try   {   outbound.close();}   catch   (Exception   e2)   {}  
                }  
          }  
   
   
          void   pipe(InputStream   is0,   InputStream   is1,  
                    OutputStream   os0,     OutputStream   os1)   throws   IOException   {  
  try   {  
          int   ir;  
          byte   bytes[]=new   byte[BUFSIZ];  
          while   (true)   {  
  try   {  
          if   ((ir=is0.read(bytes))>0)   {  
  os0.write(bytes,0,ir);  
  if   (logging)   writeLog(bytes,0,ir,true);  
          }  
          else   if   (ir<0)  
  break;  
  }   catch   (InterruptedIOException   e)   {   }  
  try   {  
          if   ((ir=is1.read(bytes))>0)   {  
  os1.write(bytes,0,ir);  
  if   (logging)   writeLog(bytes,0,ir,false);  
          }  
          else   if   (ir<0)    
  break;  
  }   catch   (InterruptedIOException   e)   {   }  
          }  
  }   catch   (Exception   e0)   {  
          System.out.println("Pipe异常:   "   +   e0);  
  }  
          }  
   
   
          static   public   void   startProxy(int   port,Class   clobj)   {  
  ServerSocket   ssock;  
  Socket   sock;  
                  try   {  
          ssock=new   ServerSocket(port);  
          while   (true)   {  
  Class   []   sarg   =   new   Class[1];  
  Object   []   arg=   new   Object[1];  
  sarg[0]=Socket.class;  
  try   {  
          java.lang.reflect.Constructor   cons   =   clobj.getDeclaredConstructor(sarg);  
          arg[0]=ssock.accept();  
          cons.newInstance(arg);   //   创建HttpProxy或其派生类的实例  
  }   catch   (Exception   e)   {    
          Socket   esock   =   (Socket)arg[0];  
          try   {   esock.close();   }   catch   (Exception   ec)   {}  
  }  
          }  
  }   catch   (IOException   e)   {  
  }  
          }  
   
   
          //   测试用的简单main方法  
          static   public   void   main(String   args[])   {  
  System.out.println("在端口808启动代理服务器\n");  
  HttpProxy.log=System.out;  
  HttpProxy.logging=false;  
  HttpProxy.startProxy(808,HttpProxy.class);  
              }  
          }  
  //   HttpProxy的简单派生类  
  //   不记录主机名字  
  //   在日志输出的每一行前面加上一个'*'  
   
  import   java.io.*;  
  import   java.net.*;  
   
  public   class   SubHttpProxy   extends   HttpProxy   {  
          static   private   boolean   first=true;  
          public   SubHttpProxy(Socket   s)   {  
  super(s);  
          }  
          public   void   writeLog(int   c,   boolean   browser)   throws   IOException   {  
  if   (first)   log.write('*');  
  first=false;  
  log.write(c);  
  if   (c=='\n')   log.write('*');  
          }  
          public   String   processHostName(String   url,   String   host,   int   port,   Socket   sock)   {  
  //   直接返回  
  return   host;  
          }  
          //   测试用的简单main方法  
          static   public   void   main(String   args[])   {  
  System.out.println("在端口808启动代理服务器\n");  
  HttpProxy.log=System.out;  
  HttpProxy.logging=true;  
  HttpProxy.startProxy(808,SubHttpProxy.class);  
              }  
   
   
  }  
posted on 2008-10-21 02:02 聂文龙 阅读(171) 评论(10)  编辑 收藏 引用

FeedBack:
# re: 代理服务器代码 2008-10-21 02:03 聂文龙
不要心里老是想着只要拿到源代码就可以直接去用,因为对rfc1928、rfc1929研究是必要的,因为在调试程序的时候,你一定要知道协议才可以调,我现在给一些相关的文档给你,也许比那些代码对你更加有用处:

用socks5进行udp发送数据的过程:

你的目的是要和服务器做UDP的数据传送。
步骤:
1,和代理建立tcp联接,(你已经完成)
2,向代理发送版本的请求信息,
我的实现:
void CCommunicator::SendVer ()
{
int datasize = 6;
char tempbuf[6];

tempbuf[0] = 5;
tempbuf[1] = 4;//标示后面所根的字接数
tempbuf[2] = 0;
tempbuf[3] = 1;
tempbuf[4] = 2;
tempbuf[5] = 3;
int senddatalen;
senddatalen = send(m_sock, (char *)tempbuf, 6, 0 );
}
这一步,你已经返回成功,是吗?
如果失败,断开建立的tcp联接,
如果成功,如果需要用户验证则进行步骤3,否则进行4,
3,如果需要用户验证,则
类似:
BOOL CCommunicator::SendUserTest()
{
int usernamelen=0;
int userpasslen=0;
usernamelen = m_strTestUserName.GetLength();
userpasslen = m_strTestUserPass.GetLength();
char tempbuf[100];

tempbuf[0] = 5;
tempbuf[1] = usernamelen;//标示后面所根的字接数
strcpy(&tempbuf[2],m_strTestUserName);

tempbuf[2+usernamelen] = userpasslen;
strcpy((char *)&tempbuf [3+usernamelen] ,m_strTestUserPass);

int senddatalen;
int len;
len = usernamelen +userpasslen + 3;
senddatalen = send(m_sock, (char *)tempbuf, len, 0 );
}
如果失败,断开建立的tcp联接,
如果用户返回成功,步骤4
4,发送请求的协议
类似:
void CCommunicator::SendRequestUDP ()
{

int const datasize = 10;
BYTE tempbuf[datasize];
tempbuf[0] = 5;
tempbuf[1] = 3;//标示UDP连接
tempbuf[2] = 0;
tempbuf[3] = 1;
tempbuf[4] = 0;
tempbuf[5] = 0;
tempbuf[6] = 0;
tempbuf[7] = 0;
*((SHORT*)(&(tempbuf[8]))) = m_uBindUDPPort;
//UDP在客户端绑定的端口,就是你本地机器的做udp数据传送的端口,调用
// socket函数后,再调用bind()来邦定一个端口。
char temp;
temp = tempbuf[8] ;
tempbuf[8] = tempbuf[9];
tempbuf[9] = temp;

int senddatalen = send(m_sock, (char *)tempbuf, datasize, 0 );
}
如果失败,断开建立的tcp联接,
如果返回成功,验证完毕!步骤5
5,真正的数据传送,用代理传送的时候,数据包的前面加上10个字节
类似:
void CCommunicator::CopyDataHead(BYTE * ptempbuf)
{
struct in_addr addr;
addr.s_addr = inet_addr(“202.220.33.333”);//这个ip是服务器端的ip

ptempbuf[0] = 0;
ptempbuf[1] = 0;
ptempbuf[2] = 0;
ptempbuf[3] = 1;
ptempbuf[4] = (char)addr.S_un.S_un_b.s_b1;;
ptempbuf[5] = (char)addr.S_un.S_un_b.s_b2;
ptempbuf[6] = (char)addr.S_un.S_un_b.s_b3;
ptempbuf[7] = (char)addr.S_un.S_un_b.s_b4;

*((SHORT*)(&(ptempbuf[8]))) = m_uServerUDPPort;//服务器的端口,就是你最终要发到那个服务器的端口,也就是你的qq服务器。
char temp;
temp = ptempbuf[8] ;
ptempbuf[8] = ptempbuf[9];
ptempbuf[9] = temp;
}
真正发送的时候类似:
int CCommunicator::SendBufferUDP(LPBYTE lpBuf,int nLen)
{
BYTE tempbuf[1000];
int iHeadData = 0;
struct sockaddr_in her;
her.sin_family = AF_INET;
her.sin_addr.s_addr = inet_addr(m_szProxyAddr);//代理服务器
her.sin_port = htons(m_uSocksPort);//发送请求的时候返回的代理服务器端的端口,记住,这是最重要的。
CopyDataHead(tempbuf);
iHeadData = 10;
nLen=nLen + 10;
int addr_len;
addr_len = sizeof(struct sockaddr);

CopyMemory((char *)&tempbuf[iHeadData],lpBuf,nLen);
int returndatalen = sendto(m_socket,(char *)tempbuf,nLen,0,(struct sockaddr *)&her,addr_len);

}
希望对你有帮助!  回复  更多评论
  
# re: 代理服务器代码 2008-10-21 02:04 聂文龙
传透代理服务器的编程

关键字 代理服务器、Socks4、Socks5、Http代理
原作者姓名 allfresh
文章原始出处 http://www.allfresh.net/program/proxy.htm
正文
在网络程序设计过程中,我们经常要与各种类型的代理服务器打交道,比如在企业内部网通过代理去访问Internet网上的服务器等等,一般代理服务器支持几种常见的代理协议标准,如Socks4,Socks5,Http代理,其中Socks5需要用户验证,代理相对复杂。我在查阅RFC文档和相关资料后,特总结一些TCP协议穿透代理服务器的程序片断,希望对大家有所帮助。

//使用到的结构
struct sock4req1
{
 char VN;
 char CD;
 unsigned short Port;
 unsigned long IPAddr;
 char other[1];
};

struct sock4ans1
{
 char VN;
 char CD;
};

struct sock5req1
{
 char Ver;
 char nMethods;
 char Methods[255];
};

struct sock5ans1
{
 char Ver;
 char Method;
};

struct sock5req2
{
 char Ver;
 char Cmd;
 char Rsv;
 char Atyp;
 char other[1];
};

struct sock5ans2
{
 char Ver;
 char Rep;
 char Rsv;
 char Atyp;
 char other[1];
};

struct authreq
{
 char Ver;
 char Ulen;
 char Name[255];
 char PLen;
 char Pass[255];
};

struct authans
{
 char Ver;
 char Status;
};

//通过Socks4方式代理
if( !ClientSock.Connect( g_ProxyInfo.m_strProxyIP,g_ProxyInfo.m_nProxyPort) )
{
  m_sError = _T("不能连接到代理服务器!");
  ClientSock.Close();
  return FALSE;
}
char buff[100];
memset(buff,0,100);
struct sock4req1 *m_proxyreq;
m_proxyreq = (struct sock4req1 *)buff;
m_proxyreq->VN = 4;
m_proxyreq->CD = 1;
m_proxyreq->Port = ntohs(GetPort());
m_proxyreq->IPAddr = inet_addr(GetServerHostName());
ClientSock.Send(buff,9);
struct sock4ans1 *m_proxyans;
m_proxyans = (struct sock4ans1 *)buff;
memset(buff,0,100);
ClientSock.Receive(buff,100);
if(m_proxyans->VN != 0 || m_proxyans->CD != 90)
{
 m_sError = _T("通过代理连接主站不成功!");
 ClientSock.Close();
 return FALSE;
}




//通过Socks5方式代理
if( !ClientSock.Connect( g_ProxyInfo.m_strProxyIP,g_ProxyInfo.m_nProxyPort) )
{
 m_sError = _T("不能连接到代理服务器!");
 ClientSock.Close();
 return FALSE;
}
char buff[600];
struct sock5req1 *m_proxyreq1;
m_proxyreq1 = (struct sock5req1 *)buff;
m_proxyreq1->Ver = 5;
m_proxyreq1->nMethods = 2;
m_proxyreq1->Methods[0] = 0;
m_proxyreq1->Methods[1] = 2;
ClientSock.Send(buff,4);
struct sock5ans1 *m_proxyans1;
m_proxyans1 = (struct sock5ans1 *)buff;
memset(buff,0,600);
ClientSock.Receive(buff,600);
if(m_proxyans1->Ver != 5 || (m_proxyans1->Method!=0 && m_proxyans1->Method!=2))
{
 m_sError = _T("通过代理连接主站不成功!");
 ClientSock.Close();
 return FALSE;
}
if(m_proxyans1->Method == 2)
{
 int nUserLen = strlen(g_ProxyInfo.m_strProxyUser);
 int nPassLen = strlen(g_ProxyInfo.m_strProxyPass);
 struct authreq *m_authreq;
 m_authreq = (struct authreq *)buff;
 m_authreq->Ver = 1;
 m_authreq->Ulen = nUserLen;
 strcpy(m_authreq->Name,g_ProxyInfo.m_strProxyUser);
 m_authreq->PLen = nPassLen;
 strcpy(m_authreq->Pass,g_ProxyInfo.m_strProxyPass);
 ClientSock.Send(buff,513);
 struct authans *m_authans;
 m_authans = (struct authans *)buff;
 memset(buff,0,600);
 ClientSock.Receive(buff,600);
 if(m_authans->Ver != 1 || m_authans->Status != 0)
 {
  m_sError = _T("代理服务器用户验证不成功!");
  ClientSock.Close();
 return FALSE;
 }
}
struct sock5req2 *m_proxyreq2;
m_proxyreq2 = (struct sock5req2 *)buff;
m_proxyreq2->Ver = 5;
m_proxyreq2->Cmd = 1;
m_proxyreq2->Rsv = 0;
m_proxyreq2->Atyp = 1;
unsigned long tmpLong = inet_addr(GetServerHostName());
unsigned short port = ntohs(GetPort());
memcpy(m_proxyreq2->other,&tmpLong,4);
memcpy(m_proxyreq2->other+4,&port,2);
ClientSock.Send(buff,sizeof(struct sock5req2)+5);
struct sock5ans2 *m_proxyans2;
memset(buff,0,600);
m_proxyans2 = (struct sock5ans2 *)buff;
ClientSock.Receive(buff,600);
if(m_proxyans2->Ver != 5 || m_proxyans2->Rep != 0)
{
 m_sError = _T("通过代理连接主站不成功!");
 ClientSock.Close();
 return FALSE;
}




//通过HTTP方式代理
if( !ClientSock.Connect( g_ProxyInfo.m_strProxyIP,g_ProxyInfo.m_nProxyPort) )
{
 m_sError = _T("不能连接到代理服务器!");
 ClientSock.Close();
 return FALSE;
}
char buff[600];
sprintf( buff, "%s%s:%d%s","CONNECT ",GetServerHostName(),GetPort()," HTTP/1.1\r\nUser-Agent: MyApp/0.1\r\n\r\n");
ClientSock.Send(buff,strlen(buff)); //发送请求
memset(buff,0,600);
ClientSock.Receive(buff,600);
if(strstr(buff, "HTTP/1.0 200 Connection established") == NULL) //连接不成功
{
 m_sError = _T("通过代理连接主站不成功!");
 ClientSock.Close();
 return FALSE;
}


我们一般先与代理服务器连通,然后向代理服务器发送代理验证的用户名和密码(如果需要,如Socks5代理),验证成功后,再向代理服务器发送需要连接的目的地址和端口。以上代码仅用于TCP连接,如果在内部网侦听或通过UDP协议发送信息,可查阅RFC1829等文档资料。

<正文完>   回复  更多评论
  
# re: 代理服务器代码 2008-10-21 02:08 聂文龙
使用socks4 socks5 http代理的客户端

///定义的结构
struct sock4req1
{
char VN;
char CD;
unsigned short Port;
unsigned long IPAddr;
char other[1];
};

struct sock4ans1
{
char VN;
char CD;
};

struct sock5req1
{
char Ver;
char nMethods;
char Methods[255];
};

struct sock5ans1
{
char Ver;
char Method;
};

struct sock5req2
{
char Ver;
char Cmd;
char Rsv;
char Atyp;
unsigned long IPAddr;
unsigned short Port;

// char other[1];
};

struct sock5ans2
{
char Ver;
char Rep;
char Rsv;
char Atyp;
char other[1];
};

struct authreq
{
char Ver;
char Ulen;
char Name[255];
char PLen;
char Pass[255];
};

struct authans
{
char Ver;
char Status;
};


///////////
///////////代码片段
void CTestDlg::OnSocks4()
{
CString m_sError;
ClientSock.Create();

//Socks4代理服务器端口及地址
//if( !ClientSock.Connect( "195.65.215.38",1080) )
if( !ClientSock.Connect( "192.168.123.194",1080) )
{
m_sError = _T("不能连接到代理服务器!");
ClientSock.Close();
MessageBox(m_sError);
return ;
}

char buff[100];
memset(buff,0,100);
struct sock4req1 *m_proxyreq;
m_proxyreq = (struct sock4req1 *)buff;
m_proxyreq->VN = 4;
m_proxyreq->CD = 1;
m_proxyreq->Port = ntohs(21);
m_proxyreq->IPAddr = inet_addr("219.201.39.50");
strcpy(m_proxyreq->other , "");
ClientSock.Send(buff,9);
struct sock4ans1 *m_proxyans;
m_proxyans = (struct sock4ans1 *)buff;
memset(buff,0,100);
ClientSock.Receive(buff,100);
if(m_proxyans->VN != 0 || m_proxyans->CD != 90)
{
m_sError = _T("通过代理连接主站不成功!");
ClientSock.Close();
MessageBox(m_sError);
return ;
}



//连接已经建立,发送及接收数据
memset(buff,0,100);
strcpy(buff,"Hello!");
ClientSock.Send(buff,sizeof(buff));
memset(buff,0,100);
ClientSock.Receive(buff,100);
MessageBox(buff);
ClientSock.Close();

}

void CTestDlg::OnSocks5()
{
// TODO: Add your control notification handler code here
//http://my.nbip.net/homepage/nblulei/ttdl/sockdllb.htm

CString m_sError;
ClientSock.Create();
//Socks5代理服务器端口及地址
//if( !ClientSock.Connect("61.238.12.84",12654) )
if( !ClientSock.Connect("192.168.123.194",1080) )
{
m_sError = _T("不能连接到代理服务器!");
ClientSock.Close();
MessageBox(m_sError);
return ;
}
char buff[600];
struct sock5req1 *m_proxyreq1;
m_proxyreq1 = (struct sock5req1 *)buff;
m_proxyreq1->Ver = 5;
m_proxyreq1->nMethods = 2;
m_proxyreq1->Methods[0] = 0;
m_proxyreq1->Methods[1] = 2;
ClientSock.Send(buff,4);
struct sock5ans1 *m_proxyans1;
m_proxyans1 = (struct sock5ans1 *)buff;
memset(buff,0,600);
ClientSock.Receive(buff,600);
if(m_proxyans1->Ver != 5 || (m_proxyans1->Method!=0 && m_proxyans1->Method!=2))
{
m_sError = _T("通过代理连接主站不成功!");
ClientSock.Close();
MessageBox(m_sError);
return ;
}
if(m_proxyans1->Method == 2)
{
int nUserLen = strlen("alon");
int nPassLen = strlen("alon");
struct authreq *m_authreq = {0};
m_authreq = (struct authreq *)buff;
m_authreq->Ver = 1;
m_authreq->Ulen = nUserLen;
strcpy(m_authreq->Name,"alon");
m_authreq->PLen = nPassLen;
strcpy(m_authreq->Pass,"alon");
ClientSock.Send(buff,513);
struct authans *m_authans;
m_authans = (struct authans *)buff;
memset(buff,0,600);
ClientSock.Receive(buff,600);
if(m_authans->Ver != 1 || m_authans->Status != 0)
{
m_sError = _T("代理服务器用户验证不成功!");
ClientSock.Close();
MessageBox(m_sError);
return ;
}
}
struct sock5req2 *m_proxyreq2;
m_proxyreq2 = (struct sock5req2 *)buff;
m_proxyreq2->Ver = 5;
m_proxyreq2->Cmd = 1;
m_proxyreq2->Rsv = 0;
m_proxyreq2->Atyp = 1;
m_proxyreq2->IPAddr = inet_addr("219.201.39.50");
m_proxyreq2->Port = ntohs(21);


ClientSock.Send(buff,sizeof(struct sock5req2));
struct sock5ans2 *m_proxyans2;
memset(buff,0,600);
m_proxyans2 = (struct sock5ans2 *)buff;
ClientSock.Receive(buff,600);
if(m_proxyans2->Ver != 5 || m_proxyans2->Rep != 0)
{
m_sError = _T("通过代理连接主站不成功!");
ClientSock.Close();
MessageBox(m_sError);
return ;
}



//连接已经建立,发送及接收数据
memset(buff,0,600);
strcpy(buff,"Hello!");
ClientSock.Send(buff,sizeof(buff));
memset(buff,0,600);
ClientSock.Receive(buff,600);
MessageBox(buff);
ClientSock.Close();
}


void CTestDlg::OnHttp()
{
// TODO: Add your control notification handler code here
CString m_sError;
ClientSock.Create();
//if( !ClientSock.Connect("61.145.123.202",3128) )
if( !ClientSock.Connect("211.92.143.19",3128) )
//if( !ClientSock.Connect("WWW.TOM.COM",80) )
{
m_sError = _T("不能连接到代理服务器!");
ClientSock.Close();
MessageBox(m_sError);
return ;
}

char buff[600] = {0};
// sprintf( buff, "%s%s:%d%s","CONNECT ","219.201.39.50",21," HTTP/1.1\r\nUser-Agent: MyApp/0.1\r\n\r\n");
sprintf( buff, "%s%s:%d%s","CONNECT ","219.201.39.50",21," HTTP/1.1\r\nUser-Agent: CERN-LineMode/2.15 libwww/2.17b3\r\n\r\n");
// sprintf( buff, "%s%s:%d%s","CONNECT ","www.tom.com",80," HTTP/1.1\r\nUser-Agent: CERN-LineMode/2.15 libwww/2.17b3\r\n\r\n");
// sprintf( buff, "%s%s","GET ","HTTP://WWW.TOM.COM HTTP/1.1\r\n\r\n");

ClientSock.Send(buff,strlen(buff)); //发送请求
memset(buff,0,600);
ClientSock.Receive(buff,600);
if(strstr(buff, "HTTP/1.0 200 Connection established") == NULL) //连接不成功
{
m_sError = _T("通过代理连接主站不成功!");
ClientSock.Close();
return ;
}


/* if( strstr(buff, "Error 403") )
{
//return GoError(PROXYERROR_PROXYDISABLE); //代理服务器拒绝请求
}

if( strstr(buff, "407 Proxy authentication required") ) //需要身份验证
{
//return GoError(PROXYERROR_USERNAMEORPASSWORD); //用户身份校检不成功
}
if( strstr(buff, "Connection refuesed") )
{
//return GoError(PROXYERROR_CONNECTHOSTSERVER); //通过代理连接主站不成功
}
if( strstr(buff, "Access Denied") )
{
//return GoError(PROXYERROR_USERNAMEORPASSWORD); //用户身份校检不成功
}
if(strstr(buff, "Connection refused by Remote Host") )
{
//return GoError(PROXYERROR_CONNECTHOSTSERVER); //通过代理连接主站不成功
}

ClientSock.Close();
*/




//连接已经建立,发送及接收数据
memset(buff,0,600);
strcpy(buff,"Hello!");
ClientSock.Send(buff,sizeof(buff));
memset(buff,0,600);
ClientSock.Receive(buff,600);
MessageBox(buff);
ClientSock.Close();


}


/////////
///另附一些http的请求和返回
发送一:
CONNECT 61.135.158.91:80 HTTP/1.1
User-Agent: MyApp/0.1


发送二:
CONNECT 61.135.158.91:80 HTTP/1.1
User-Agent: CERN-LineMode/2.15 libwww/2.17b3


发送三:
CONNECT 127.0.0.1:2222 HTTP/1.0
User-agent: MyApp/1.0
Proxy-authorization: enter xxxxxx


接收一:
HTTP/1.0 403 Forbidden
Server: Topproxy-2.0/
Mime-Version: 1.0
Date: Thu, 18 Nov 2004 16:37:53 GMT
Content-Type: text/html
Content-Length: 718
Expires: Thu, 18 Nov 2004 16:37:53 GMT
X-Squid-Error: ERR_ACCESS_DENIED 0
X-Cache: MISS fro


接收二:
HTTP/1.0 502 Proxy Error ( SSL port specified is not allowed. )
Via: 1.0 PROXY
Pragma: no-cache
Cache-Control: no-cache
Content-Type: text/html

<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
<html>

<head>
<meta http-equiv="Conten"


接收三:
HTTP/1.1 403 Forbidden
Date: Sat, 20 Nov 2004 14:33:13 GMT
Content-Length: 257
Content-Type: text/html
Server: NetCache appliance (NetApp/5.6R1D6)

<HTML>
<HEAD><TITLE>403 Forbidden</TITLE></HEAD>
<BODY>
<H1>Forbidden</H1>
<H4>
You were"



  回复  更多评论
  
# re: 代理服务器代码 2008-10-21 02:12 聂文龙
简单代理服务器C代码实现(SOLARIS)

/*
** 编写:无可非议
** 来源:WWW.20CN.NET
** 注意:请注明转贴来源
*/

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <signal.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <sys/wait.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <pthread.h>
#include <sys/stat.h>

int m_MainId = 0; //主进程ID
int m_ListenSocket = 0; //侦听套接字
char m_ConnectAddr[256] = {0}; //目标地址
char m_ConnectPort[256] = {0}; //目标端口

/*
** 函数名称: GetListenSocket
** 函数功能: 生成侦听套接字
** 传入参数: Port : 侦听端口
** 传出参数: 无
** 引用函数: 无
** 返回值 : 侦听套接字,为0时表示生成套接字失败,其他为套接字句柄
** 备注 : 无
*/
int GetListenSocket(int Port)
{
struct sockaddr_in m_LisAddr = {0};
int m_Socket = 0;
int m_AddrLen = sizeof(struct sockaddr_in);

//配置端口信息
m_LisAddr.sin_family = AF_INET;
m_LisAddr.sin_port = htons(Port);
m_LisAddr.sin_addr.s_addr = INADDR_ANY;

//创建套接字
if ((m_Socket = socket(AF_INET,SOCK_STREAM,0)) < 0 )
{
//创建套接字失败
return 0;
}

//绑定套接字
if(bind(m_Socket, (sockaddr*)&m_LisAddr , m_AddrLen) < 0 )
{
//绑定套接字失败
close(m_Socket);
return 0;
}

//侦听套接字
if(listen(m_Socket,5))
{
//侦听套接字失败
close(m_Socket);
return 0;
}

//侦听套接字生成成功
return m_Socket;
}

/*
** 函数名称: GetConnectSocket
** 函数功能: 生成连接套接字
** 传入参数: pServerAddr : 连接地址 pServerPort : 连接端口
** 传出参数: 无
** 引用函数: 无
** 返回值 : 连接套接字,为0时表示生成套接字失败,其他为套接字句柄
** 备注 : 无
*/
int GetConnectSocket(char* pServerAddr,char* pServerPort)
{
struct sockaddr_in m_ServerAddr = {0};
int m_AddrLen = sizeof(struct sockaddr_in);
int m_Socket = 0;

//初始化连接信息
m_ServerAddr.sin_addr.S_un.S_addr = inet_addr(pServerAddr);
m_ServerAddr.sin_port = htons(atoi(pServerPort));
m_ServerAddr.sin_family = AF_INET;

//创建发送套接字
m_Socket = socket(AF_INET,SOCK_STREAM,0);
if(m_Socket <= 0)
{
//失败
return NULL;
}

//连接客户计算机
if(connect(m_Socket,(sockaddr*)&m_ServerAddr,m_AddrLen) < 0 )
{
close(m_Socket);
return NULL;
}

//连接成功
return m_Socket;
}

/*
** 函数名称: TransSocket
** 函数功能: 完成套接字数据转发
** 传入参数: m_SendSocket : 发送套接字 m_RecvSocket : 接收套接字
** 传出参数: 无
** 引用函数: 无
** 返回值 : 无
** 备注 : 逆反完成全双工
*/
void TransSocket(int m_SendSocket,int m_RecvSocket)
{
char m_Buf[512 * 1024] = {0};
int ret = 0;
fd_set readset;
struct timeval tm = {0};
tm.tv_sec = 3600 * 24;

FD_ZERO(&readset);
FD_SET(m_RecvSocket,&readset);

while(1)
{
if((select(m_RecvSocket + 1,&readset,NULL,NULL,&tm)
<= 0))
{
//出错
break;
}
if(!FD_ISSET(m_RecvSocket,&readset)) continue;

ret = recv(m_RecvSocket,m_Buf,512 * 1024 - 1,0);
if(ret < 0)
{
//出错
break;
}
send(m_SendSocket,m_Buf,ret,0);
}
close(m_SendSocket);
close(m_RecvSocket);
}

/*
** 函数名称: SocketTrans
** 函数功能: 工作主函数,完成数据转发,新进程启动
** 传入参数: m_SendSocket : 发送套接字 m_RecvSocket : 接收套接字
** 传出参数: 无
** 引用函数: 无
** 返回值 : 无
** 备注 : 逆反完成全双工
*/
void SocketTrans()
{
struct sockaddr_in m_WorkAddr = {0};
int m_191Socket = 0;
int m_147socket = 0;
int m_WorkAddrLen = 0;

//开始任务执行
while(1)
{
//接受147的连接
m_WorkAddrLen = sizeof(struct sockaddr_in);
m_147socket = accept(m_ListenSocket,
(sockaddr*)&m_WorkAddr , &m_WorkAddrLen);

//检查套接字合法性
if(m_147socket < 0) continue;

//连接191
m_191Socket = GetConnectSocket(m_ConnectAddr,m_ConnectPort);
if(m_191Socket == NULL)
{
close(m_147socket);
continue;
}

int ret = fork();
if(ret < 0)
{
//建立新进程失败
printf("致命错误,无法建立新进程!\n");
fflush(stdout);
close(m_191Socket);
close(m_147socket);
break;
}
else if(ret == 0)
{
//关闭原来端口
close(m_ListenSocket);

//建立二次子进程,防止僵尸进程
ret = fork();
if(ret < 0)
{
close(m_191Socket);
close(m_147socket);
_exit(0);
}
else if(ret == 0)
{
//接收进程
TransSocket(m_191Socket,m_147socket);
_exit(0);
}
ret = fork();
if(ret < 0)
{
close(m_191Socket);
close(m_147socket);
_exit(0);
}
else if(ret == 0)
{
//发送进程
TransSocket(m_147socket,m_191Socket);
_exit(0);
}
close(m_191Socket);
close(m_147socket);
_exit(0);
}

//等待子线程结束
close(m_191Socket);
close(m_147socket);
waitpid(ret,NULL,0);
}
}

/*
** 函数名称: sig_usr
** 函数功能: 进程信号处理函数
** 传入参数: 无
** 传出参数: 无
** 引用函数: 无
** 返回值 : 无
** 备注 : 处理进程终止事件
*/
static void sig_usr(int signo)
{
close(m_ListenSocket);
if(m_MainId == getpid())
kill(0,SIGKILL);
exit(0);
}

static void sig_ign(int signo)
{
fprintf(stderr,"signal %d catched ,ignoring\n",signo);
}

int daemon_init()
{
pid_t pid;
if((pid=fork())<0){
return -1;
}else if(pid!=0){
exit(0);
}
setsid();
umask(0);
return 0;
}

/*
** 函数名称: main
** 函数功能: 进程主函数
** 传入参数: 无
** 传出参数: 无
** 引用函数: MakeFilePath,GetMyInitInfo,SocketTrans
** 返回值 : 无
** 备注 : 为客户接收进程主函数
*/
int main(int argc,char* argv[])
{
//检查参数合法性
if(argc != 4)
{
printf("格式:本地端口 目的地址 目的端口\n");
fflush(stdout);
return 0;
}

daemon_init();

//登记信号事件
signal(SIGTERM,sig_usr);
signal(SIGINT,sig_usr);
signal(SIGQUIT,sig_usr);
signal(SIGPIPE,sig_ign);
signal(SIGALRM,sig_ign);
signal(SIGQUIT,sig_ign);
signal(SIGFPE,sig_ign);
signal(SIGILL,sig_ign);
signal(SIGPIPE,sig_ign);
signal(SIGSEGV,sig_ign);
signal(SIGTRAP,sig_ign);
signal(SIGTSTP,sig_ign);

//取参数
strcpy(m_ConnectAddr,argv[2]);
strcpy(m_ConnectPort,argv[3]);

//获取侦听套接字
m_ListenSocket = GetListenSocket(atoi(argv[1]));
if(m_ListenSocket == 0)
{
printf("侦听端口[%s]失败!\n",argv[1]);
fflush(stdout);
return 0;
}

m_MainId = getpid();
//启动文件接收侦听线程
SocketTrans();
close(m_ListenSocket);
return 0;
}
  回复  更多评论
  
# re: 代理服务器代码 2008-10-21 02:19 聂文龙
#include "stdafx.h"
#include "Proxy.h"
#include < winsock2.h > //WINSOCKET API 2。0
#include < stdlib.h >
#include < stdio.h >
#include < string.h >


#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif


/////////////////////////////////////////////////////////////////////////////


#define HTTP "http://"
#define FTP "ftp://"
#define PROXYPORT 5001 //Proxy 端口
#define BUFSIZE 10240 //缓冲区大小


CWinApp theApp;


using namespace std;


UINT ProxyToServer(LPVOID pParam);
UINT UserToProxyThread(void *pParam);


strUCt SocketPair{
SOCKET user_proxy; //socket : 本地机器到PROXY 服务机
SOCKET proxy_server; //socket : PROXY 服务机到远程主机
BOOL IsUser_ProxyClosed; // 本地机器到PROXY 服务机状态
BOOL IsProxy_ServerClosed; // PROXY 服务机到远程主机状态
};


struct ProxyParam{
char Address[256]; // 远程主机地址
HANDLE User_SvrOK; // PROXY 服务机到远程主机的联结状态
SocketPair *pPair; // 维护一组SOCKET的指针
int Port; // 用来联结远程主机的端口
}; //这个结构用来PROXY SERVER与远程主机的信息交换.


SOCKET gListen_Socket; //用来侦听的SOCKET。


int StartServer() //启动服务
{
WSADATA wsaData;
sockaddr_in local;
SOCKET listen_socket;


if(::WSAStartup(0x202,&wsaData)!=0)
{printf("\nError in Startup session.\n");WSACleanup();return -1;};



local.sin_family=AF_INET;

local.sin_addr.s_addr=INADDR_ANY;
local.sin_port=htons(PROXYPORT);


listen_socket=socket(AF_INET,SOCK_STREAM,0);
if(listen_socket==INVALID_SOCKET)
{printf("\nError in New a Socket.");WSACleanup();return -2;}


if(::bind(listen_socket,(sockaddr *)&local,sizeof(local))!=0)
{printf("\n Error in Binding socket."); WSACleanup();return -3; };


if(::listen(listen_socket,5)!=0)
{printf("\n Error in Listen."); WSACleanup(); return -4;}
gListen_Socket=listen_socket;
AfxBeginThread(UserToProxyThread,NULL); //启动侦听
return 1;
}


int CloseServer() //关闭服务
{
closesocket(gListen_Socket);
WSACleanup();
return 1;
}
//分析接收到的字符,得到远程主机地址


int GetAddressAndPort( char * str, char *address, int * port)
{
char buf[BUFSIZE], command[512], proto[128], *p;
int j;
sscanf(str,"%s%s%s",command,buf,proto);
p=strstr(buf,HTTP);
//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


} //End While


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
return 0;
}


// 读取远程主机数据,并发往本地客户机
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;
}
#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;
}
  回复  更多评论
  
# re: 代理服务器代码 2008-10-21 02:22 聂文龙
打造自己的HTTP代理服务器
#include "stdafx.h"
#include "HTTPPROXY.h"
#define FD_NOEVENT 0
//
#define BACKUP 100
#define MAXDATALEN 65535
int HttpListenPort;
SOCKET HttpListenSock;
//
typedef struct _CLIENTINFO{
SOCKET clientsock;
SOCKET udpsock;
sockaddr_in clientsock_addr;
}CLIENTINFO,*LPCLIENTINFO;
CLIENTINFO HttpClientInfo;
//
typedef struct _SOCKINFO{
SOCKET sourcesock;
SOCKET destsock;
}SOCKINFO,*LPSOCKINFO;
SOCKINFO httpsockinfo;
//
extern long GetSocketEventId(SOCKET remotesock);
extern unsigned long GetLocalIp();
extern unsigned long GetDomainIp(char domainname[250]);
/*
long GetSocketEventId(SOCKET remotesock){
long EventId;
HANDLE hevent;
hevent=CreateEvent(NULL,0,0,0);
WSANETWORKEVENTS socket_events;
EventId=FD_NOEVENT;
if(WSAEventSelect(remotesock,hevent,FD_ACCEPT|FD_CONNECT|FD_
READ|FD_WRITE|FD_CLOSE)==SOCKET_ERROR) return EventId;
WSAEnumNetworkEvents(remotesock,hevent,&socket_events);
if(socket_events.lNetworkEvents!=0){
switch(socket_events.lNetworkEvents){
case FD_ACCEPT:EventId=FD_ACCEPT;break;
case FD_CONNECT:EventId=FD_CONNECT;break;
case FD_READ:EventId=FD_READ;break;
case FD_WRITE:EventId=FD_WRITE;break;
case FD_CLOSE:EventId=FD_CLOSE;break;
case FD_OOB:EventId=FD_OOB;break;
default:EventId=FD_NOEVENT;break;
}
}
else EventId=FD_NOEVENT;
return EventId;
}
//
unsigned long GetLocalIp()
{
char IP[MAX_PATH],*ip;
char pc_name[80];
struct in_addr in;
struct hostent *host;
WORD wVersionRequested;
WSADATA wsaData;
wVersionRequested=MAKEWORD(2,0);
ip=IP;
strcpy(ip,"Ip not get!");
if(WSAStartup(wVersionRequested,&wsaData)) return 0;
if(gethostname(pc_name,80)==SOCKET_ERROR){
WSACleanup();
return 0;
}
if(!(host=gethostbyname(pc_name))){
WSACleanup();
return 0;
}
in.s_addr=*((unsigned long *)host->h_addr_list[0]);
strcpy(ip,inet_ntoa(in));
WSACleanup();
return in.s_addr;
}
//
unsigned long GetDomainIp(char domainname[250])
{
char IP[MAX_PATH],*ip;
struct in_addr in;
struct hostent *host;
WORD wVersionRequested;
WSADATA wsaData;
wVersionRequested=MAKEWORD(2,0);
ip=IP;
strcpy(ip,"Ip not get!");
if(WSAStartup(wVersionRequested,&wsaData)) return 0;
if(!(host=gethostbyname(domainname))){
WSACleanup();
return 0;
}
in.s_addr=*((unsigned long *)host->h_addr_list[0]);
strcpy(ip,inet_ntoa(in));
WSACleanup();
return in.s_addr;
}
*/
//
//
UINT HttpReciveThread(LPVOID info){ //针对客户端的接收处理线程
LPSOCKINFO psockinfo;
SOCKET sourcesock,destsock;
char data[MAXDATALEN];
long eventid;
int datalen;
psockinfo=(LPSOCKINFO)info;
sourcesock=psockinfo->sourcesock;
destsock=psockinfo->destsock;
TRACE("deail recive thread ok!\r\n");
while(true){
eventid=GetSocketEventId(sourcesock);
switch(eventid){
case FD_CLOSE:
TRACE("s fdclosed\r\n");
closesocket(destsock);
return 1;
break;
default:break;
}
eventid=GetSocketEventId(destsock);
switch(eventid){
case FD_CLOSE:
closesocket(sourcesock);
TRACE("d fdclosed\r\n");
return 1;
break;
default:break;
}
datalen=recv(sourcesock,data,sizeof(data),0);
if(datalen==0){
closesocket(sourcesock);
closesocket(destsock);
TRACE("s fdclosed\r\n");
break;
}
if(datalen>0){
while(!send(destsock,data,datalen,0));
}
Sleep(1);
}
return 1;
}
//
UINT HttpSendThread(LPVOID info){ //针对远程端的接收处理线程
LPSOCKINFO psockinfo;
SOCKET sourcesock,destsock;
char data[MAXDATALEN];
long eventid;
int datalen;
psockinfo=(LPSOCKINFO)info;
sourcesock=psockinfo->sourcesock;
destsock=psockinfo->destsock;
TRACE("deail send thread ok!\r\n");
while(true){
eventid=GetSocketEventId(sourcesock);
switch(eventid){
case FD_CLOSE:
TRACE("s fdclosed\r\n");
closesocket(destsock);
return 1;
break;
default:break;
}
eventid=GetSocketEventId(destsock);
switch(eventid){
case FD_CLOSE:
closesocket(sourcesock);
TRACE("d fdclosed\r\n");
return 1;
break;
default:break;
}
datalen=recv(destsock,data,sizeof(data),0);
if(datalen==0){
closesocket(sourcesock);
closesocket(destsock);
TRACE("d fdclosed\r\n");
break;
}
if(datalen>0){
while(!send(sourcesock,data,datalen,0));
}
Sleep(1);
}
return 1;
}
//
//
UINT HttpProxyServerThread(LPVOID info){ //针对一次服务的线程
LPCLIENTINFO pclientinfo;
SOCKET connectsock,clientsock;
sockaddr_in remotesock_addr;
char data[MAXDATALEN],url[250],temp[250],httpurl[250],portnum[10];
int datalen,i,index_start,index_end,port;
CString HttpString,UrlString,PortString;
pclientinfo=(LPCLIENTINFO)info;
clientsock=pclientinfo->clientsock;
ZeroMemory((void *)data,sizeof(data));
datalen=recv(clientsock,data,sizeof(data),0);
if(datalen<=0){
closesocket(clientsock);
return 0;
}
HttpString.Format("%s",data);
UrlString=HttpString;
TRACE("get http string:\r\n");
TRACE(HttpString);
index_start=HttpString.Find("Host: ",0); //寻找url标记
if(index_start<=0){
closesocket(clientsock);
return 0;
}
index_end=HttpString.Find("\r\n",index_start);
if(index_end<=0){
closesocket(clientsock);
return 0;
}
UrlString=HttpString.Mid(index_start+6,index_end-index_start-6); //读取 url字符串
TRACE("\r\n get url:");
TRACE(UrlString);
wsprintf(url,"%s",UrlString);
strcpy(temp,url);
strcat(temp,":");
datalen=strlen(temp);
if(HttpString.Find("GET",0)==0){ //判断get命令,并处理
index_start=HttpString.Find(temp,0);
strcpy(httpurl,"http://");
if(index_start>0){
index_end=HttpString.Find("/",index_start);
if(index_end<=0){
closesocket(clientsock);
return 0;
}
PortString=HttpString.Mid(index_start+datalen,index_end-index_start-datalen);
port=atoi(PortString);
strcat(httpurl,temp);
itoa(port,portnum,sizeof(portnum));
strcat(httpurl,portnum);
strcat(httpurl,"/");
}
else{
port=80;
strcat(httpurl,url);
strcat(httpurl,"/");
}
TRACE("get http url:%s\r\n",httpurl);
HttpString.Replace(httpurl,"/");
HttpString.Replace("Proxy-","");
HttpString.Replace("HTTP/1.0","HTTP/1.1");
}
else if(HttpString.Find("CONNECT",0)==0){ //判断connect命令并处理
index_start=HttpString.Find(temp,0);
if(index_start>0){
index_end=HttpString.Find(" ",index_start);
if(index_end<=0){
closesocket(clientsock);
return 0;
}
PortString=HttpString.Mid(index_start+datalen,index_end-index_start-datalen);
port=atoi(PortString);
}
else{
closesocket(clientsock);
return 0;
}
}
TRACE("get new http string:\r\n");
TRACE(HttpString);
remotesock_addr.sin_family=AF_INET;
remotesock_addr.sin_port=htons(port);
remotesock_addr.sin_addr.S_un.S_addr=GetDomainIp(url);
connectsock=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
if(connect(connectsock,(const sockaddr *)&remotesock_addr,sizeof(remotesock_addr))==INVALID_SOCKET){ //连接远程主机
closesocket(clientsock);
return 0;
}
TRACE("\r\nconnect to remote ip ok\r\n");
ZeroMemory((void *)data,sizeof(data));
wsprintf(data,"%s",HttpString);
datalen=strlen(data);
if(HttpString.Find("CONNECT",0)<0) while(!send(connectsock,data,datalen,0));
else{
strcpy(data,"HTTP/1.0 200 Connection established\r\nProxy-agent: CHTTPPROXY V1.0 powered by shadow\r\n\r\n");
datalen=strlen(data);
while(!send(clientsock,data,datalen,0));
}
httpsockinfo.sourcesock=clientsock;
httpsockinfo.destsock=connectsock;
AfxBeginThread(HttpReciveThread,(LPVOID)&httpsockinfo); //抛出处理线程
AfxBeginThread(HttpSendThread,(LPVOID)&httpsockinfo); //
Sleep(100);
return 1;
}
//
UINT StartHttpProxy(LPVOID info){ //端口监听线程
SOCKET NewSock;
int socklen;
sockaddr_in serversock,remotesock_addr;
serversock.sin_family=AF_INET;
serversock.sin_addr.S_un.S_addr=INADDR_ANY;
serversock.sin_port=htons(HttpListenPort);
HttpListenSock=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
if(HttpListenSock==INVALID_SOCKET) return 0;
if(bind(HttpListenSock,(const sockaddr *)&serversock,
sizeof(serversock))==SOCKET_ERROR) return 0;
listen(HttpListenSock,BACKUP);
socklen=sizeof(remotesock_addr);
TRACE("start http proxy thread while\r\n");
while(true){
NewSock=accept(HttpListenSock,(sockaddr *)&remotesock_addr,&socklen);
TRACE("waitting ok...\r\n");
if(NewSock==INVALID_SOCKET){
Sleep(1);
continue;
}
ZeroMemory((void *)&HttpClientInfo,sizeof(CLIENTINFO));
HttpClientInfo.clientsock=NewSock;
HttpClientInfo.clientsock_addr=remotesock_addr;
TRACE("start proxy thread\r\n");
AfxBeginThread(HttpProxyServerThread,(LPVOID)&HttpClientInfo);
Sleep(100);
}
return 1;
}
//
CHTTPPROXY::CHTTPPROXY()
{
WSADATA WsaData;
WORD wsaVer;
wsaVer=MAKEWORD(2,0);
WsaStartupOk=false;
if(WSAStartup(wsaVer,&WsaData)!=SOCKET_ERROR) WsaStartupOk=true;
}

CHTTPPROXY::~CHTTPPROXY()
{
if(WsaStartupOk){
WSACleanup();
}
}

int CHTTPPROXY::StartProxy(int listenport)
{
HttpListenPort=listenport;
AfxBeginThread(StartHttpProxy,(LPVOID)NULL);
return 1;
}


/*=========================================================
FILE:HTTPPROXY.h
==========================================================*/
class CHTTPPROXY
{
public:
int StartProxy(int listenport);
bool WsaStartupOk;
CHTTPPROXY();
virtual ~CHTTPPROXY();

};

/*==================================================
FILE:stdafx.h
===================================================*/
#include
#include
#include
#include


注:不要忘了在link选项中添加wsock32.lib和ws2_32.lib,或在文件前部加上如下语句:
#paragma comment(lib,"wsock32.lib")
#paragma comment(lib,"ws2_32.lib")

本代码在win2k和vc6.0下编译成功~~
用法,把这几个文件添加到你的项目中,在WinMain()中添加如下代码:
CHTTPPROXY httpproxy;
httpproxy.StartProxy(7890);
有问题mailto me!


  回复  更多评论
  
# re: 代理服务器代码 2008-10-21 02:23 聂文龙
VC++6实现简单的代理服务器

本文转自CSDN的blog:http://blog.csdn.net/snaill/archive/2006/03/14/624437.aspx

#include "stdafx.h"
#include "Proxy.h"
#include < winsock2.h > //WINSOCKET API 2。0
#include < stdlib.h >
#include < stdio.h >
#include < string.h >

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////


#define HTTP "http://"
#define FTP "ftp://"
#define PROXYPORT 5001 //Proxy 端口
#define BUFSIZE 10240 //缓冲区大小


CWinApp theApp;

using namespace std;

UINT ProxyToServer(LPVOID pParam);
UINT UserToProxyThread(void *pParam);

struct SocketPair{
SOCKET user_proxy; //socket : 本地机器到PROXY 服务机
SOCKET proxy_server; //socket : PROXY 服务机到远程主机
BOOL IsUser_ProxyClosed; // 本地机器到PROXY 服务机状态
BOOL IsProxy_ServerClosed; // PROXY 服务机到远程主机状态
};


struct ProxyParam{
char Address[256]; // 远程主机地址
HANDLE User_SvrOK; // PROXY 服务机到远程主机的联结状态
SocketPair *pPair; // 维护一组SOCKET的指针
int Port; // 用来联结远程主机的端口
}; //这个结构用来PROXY SERVER与远程主机的信息交换.

SOCKET gListen_Socket; //用来侦听的SOCKET。

int StartServer() //启动服务
{
WSADATA wsaData;
sockaddr_in local;
SOCKET listen_socket;

if(::WSAStartup(0x202,&wsaData)!=0)
{printf("\nError in Startup session.\n");WSACleanup();return -1;};

local.sin_family=AF_INET;
local.sin_addr.s_addr=INADDR_ANY;
local.sin_port=htons(PROXYPORT);

listen_socket=socket(AF_INET,SOCK_STREAM,0);
if(listen_socket==INVALID_SOCKET)
{printf("\nError in New a Socket.");WSACleanup();return -2;}

if(::bind(listen_socket,(sockaddr *)&local,sizeof(local))!=0)
{printf("\n Error in Binding socket."); WSACleanup();return -3; };

if(::listen(listen_socket,5)!=0)
{printf("\n Error in Listen."); WSACleanup(); return -4;}
gListen_Socket=listen_socket;
AfxBeginThread(UserToProxyThread,NULL); //启动侦听
return 1;
}

int CloseServer() //关闭服务
{
closesocket(gListen_Socket);
WSACleanup();
return 1;
}
//分析接收到的字符,得到远程主机地址

int GetAddressAndPort( char * str, char *address, int * port)
{
char buf[BUFSIZE], command[512], proto[128], *p;
int j;
sscanf(str,"%s%s%s",command,buf,proto);
p=strstr(buf,HTTP);
//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.csdn.net/ 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

} //End While

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
return 0;
}
// 读取远程主机数据,并发往本地客户机
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;
}   回复  更多评论
  
# re: 代理服务器代码 2008-10-21 02:25 聂文龙
通过Socket5代理服务器访问网络的问题
SOCKS5

Socks5版本的协议说明参考 RFC1928,RFC1929
下面简单地罗列程序实现,不涉及详细的协议规范。首先对于TCP连接,然后再讨论UDP传输。至于通过socks5的多播通讯,有兴趣可以参考D. Chouinard的文章。

1、TCP:

// 建立流套接字
SOCKET m_socTCP=socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

// 连接到代理服务器
int nRet = connect(m_socTCP,(SOCKADDR*)&m_saiProxy,sizeof(m_saiProxy));

// Step 1: 连接代理服务器成功后,马上开始和代理协商,协商报文如下,询问服务器,版本5,是需要验证(0x02)还是不需要验证(0x00)
  +------+-------------------+------------+
  |VER | Number of METHODS | METHODS |
  +------+-------------------+------------+
  | 0x05 | 0x02 (有两个方法) | 0x00 | 0x02|
  +------+-------------------+------------+
const char reqNego[4]={(char)0x05,(char)0x02,(char)0x00,(char)0x02};
nRet = send(m_socTCP,reqNego,4,0);

// Setp 2: 代理服务器将返回两个字节的协商结果,接收协商结果
fd_set fdread;FD_ZERO(&fdread);
FD_SET(m_socTCP,&fdread);
// Last param set to NULL for blocking operation. (struct timeval*)
if((nRet=select(0,&fdread,NULL,NULL,NULL))==SOCKET_ERROR){return NC_E_PROXY_SELECT_READ|WSAGetLastError();}
char resNego[2]={'\0'};
int nRcvd=0,nCount=0;
while(1)
{
if(FD_ISSET(m_socTCP,&fdread))
{
//接收sock[0]发送来的数据
do{
nRet = recv(m_socTCP, (char*)resNego+nRcvd, 2-nRcvd,0);
if(nRet==SOCKET_ERROR){return NC_E_PROXY_RECEIVE|WSAGetLastError();}
nRcvd += nRet;
}
while((nRcvd!=2)&&(++nCount<1000));
if(nRcvd==2) break;
}
if(nCount++>=2000){return NC_E_PROXY_RECEIVE|WSAGetLastError();}
}
if(resNego[0]!=0x05 || (resNego[1]!=0x00 && resNego[1]!=0x02)){return NC_E_PROXY_PROTOCOL_VERSION|WSAGetLastError();};

// Step 3: 根据协商结果判断是否需要验证用户,如果是0x02,则需要提供验证,验证部分参考RFC1929
if(resNego[1]==0x02)
{
// 需要密码验证
char reqAuth[513]={'\0'};
BYTE byLenUser = (BYTE)strlen(m_szProxyUserName);
BYTE byLenPswd = (BYTE)strlen(m_szProxyPassword);
reqAuth[0]=0x01;
reqAuth[1]=byLenUser;
sprintf(&reqAuth[2],"%s",m_szProxyUserName);
reqAuth[2+byLenUser]=byLenPswd;
sprintf(&reqAuth[3+byLenUser],"%s",m_szProxyPassword);
//Send authentication info
int len = (int)byLenUser + (int)byLenPswd + 3;
nRet=send(m_socTCP,(const char*)reqAuth,len,0);
if (nRet==SOCKET_ERROR){return NC_E_PROXY_SEND|WSAGetLastError();}
//Now : Response to the auth request
char resAuth[2]={'\0'};
int nRcvd=0,nCount=0;
do{
nRet = recv(m_socTCP,resAuth+nRcvd,2-nRcvd,0);
if(nRet==SOCKET_ERROR){return NC_E_PROXY_RECEIVE|WSAGetLastError();}
nRcvd += nRet;
}
while((nRcvd!=2)&&(++nCount<1000));
if(nCount>=1000){return NC_E_PROXY_RECEIVE|WSAGetLastError();}
if (resAuth[1]!=0) return NC_E_PROXY_AUTHORIZE;
// 密码验证通过了
}

// Step 4: 协商完成,开始发送连接远程服务器请求,请求报文格式如下:
  +----+-----+-------+------+----------+----------+
  |VER | CMD | RSV | ATYP | DST.ADDR | DST.PORT |
  +----+-----+-------+------+----------+----------+
  | 1 |  1 | 0x00 |  1 | Variable |   2   |
  +----+-----+-------+------+----------+----------+
// CMD==0x01 表示连接, ATYP==0x01表示采用IPV4格式地址,DST.ADDR是远程服务器地址,DST.PORT是远程服务器端口
// 如果需要接受外来连接,则需要在连接完成之后,发送CMD==0x02绑定请求,代理将为此请求绑定一个套接字接受外部连接
char reqSubNego[10]={(char)0x05,(char)0x01,(char)0x00,(char)0x01,(char)0x00,(char)0x00,(char)0x00,(char)0x00,(char)0x00,(char)0x00};
*(unsigned long*)&reqSubNego[4] =m_saiServerTCP.sin_addr.S_un.S_addr;
*(unsigned short*)&reqSubNego[8]=m_saiServerTCP.sin_port;
nRet=send(m_socTCP,(const char*)reqSubNego,10,0);
if (nRet==SOCKET_ERROR){return NC_E_PROXY_SEND|WSAGetLastError();}

// Step 5: 接收对请求的响应,响应包格式如下
  +----+-----+-------+------+----------+----------+
  |VER | REP | RSV | ATYP | BND.ADDR | BND.PORT |
  +----+-----+-------+------+----------+----------+
  | 1 | 1 | 0x00 | 1   | Variable |   2   |
  +----+-----+-------+------+----------+----------+
// VER 必须是0x05, REP==0x00表示成功,ATYP==0x01表示地址是IPV4地址,BND.ADDR 是代理为连接远程服务器绑定的地址,BND.PORT是这个套接字的端口
char resSubNego1[5]={'\0'};
if(FD_ISSET(m_socTCP,&fdread))
{
int nRcvd=0,nCount=0;
do{
nRet = recv(m_socTCP,resSubNego1+nRcvd,5-nRcvd,0);
if(nRet==SOCKET_ERROR){return NC_E_PROXY_RECEIVE|WSAGetLastError();}
nRcvd += nRet;
}
while((nRcvd!=5)&&(++nCount<1000));
if(nCount>=1000){return NC_E_PROXY_RECEIVE|WSAGetLastError();}
if(resSubNego1[0]!=0x05||resSubNego1[1]!=0x00){return NC_E_PROXY_PROTOCOL_VERSION_SUB|WSAGetLastError();};

switch(resSubNego1[3])
{
case 0x01:
{
// IP V4
char resSubNego2[6]={resSubNego1[4],0};
int nRet=-1;
if(FD_ISSET(m_socTCP,&fdread))
{
int nRcvd=0,nCount=0;
do{
int nRet = recv(m_socTCP,&resSubNego2[1]+nRcvd,5-nRcvd,0);
if(nRet==SOCKET_ERROR){return NC_E_PROXY_RECEIVE|WSAGetLastError();}
nRcvd += nRet;
}
while((nRcvd!=5)&&(++nCount<1000));
if(nCount>=1000){return NC_E_PROXY_RECEIVE|WSAGetLastError();}
}
// 得到代理绑定地址
unsigned long ulBINDAddr = *(unsigned long*)&resSubNego2; // SOCKS BIND ADDR
unsigned short usBINDPort = *(unsigned short*)&resSubNego2[4]; // SOCKS BIND PORT
m_saiProxyBindTCP.sin_addr.S_un.S_addr=ulBINDAddr;
m_saiProxyBindTCP.sin_port=usBINDPort;
// 得到本机绑定地址
int len = sizeof(m_saiHostTCP);
getsockname(m_socTCP,(SOCKADDR*)&m_saiHostTCP,&len);
}
break;
case 0x03:
{
// Domain name
int nLen = resSubNego1[4]+2;
char* presSubNego2 = new char[nLen];
if(FD_ISSET(m_socTCP,&fdread))
{
int nRet=0,nRcvd=0,nCount=0;
do{
nRet = recv(m_socTCP,presSubNego2+nRcvd,nLen-nRcvd,0);
if(nRet==SOCKET_ERROR){return NC_E_PROXY_RECEIVE|WSAGetLastError();}
nRcvd += nRet;
}
while((nRcvd!=nLen)&&(++nCount<1000));
if(nCount>=1000){return NC_E_PROXY_RECEIVE|WSAGetLastError();}
}
unsigned short usBINDPort = *(unsigned short*)(presSubNego2+nLen-2); // BIND PORT;
// 此时得到的是远程主机的Domain Name
delete[] presSubNego2; presSubNego2=NULL;
}
break;
case 0x04:
{
// IPV6
AfxMessageBox("该版本不支持IPV6";
}
break;
default:
break;
}

// 至此,连接已经建立。在此套接字上可进行数据的收发。
}

2、UDP

SOCKS V5提供了对UDP的支持,它通过在代理服务器和内网主机之间建立一个UDP中继的TCP连接,来辅助进行UDP数据包的收发。此连接有一个有效期,在此有效生命周期内,必须往代理发送UDP数据报确认连接有效,来维持此连接的有效性,否则,代理服务器超时,将会自动释放此连接的资源。
下面简单地罗列程序实现,不涉及详细的协议规范。

// 客户端为UDP中继建立一个相关的流套接字
SOCKET m_socClientTCP_UdpAssociate = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

// 连接代理服务器
int nRet=connect(m_socClientTCP_UdpAssociate,(SOCKADDR*)&saiProxy,sizeof(saiProxy));

// 连接成功,开始和代理服务器协商,首先发送版本标志,方法选择报文
const char reqNego[4]={(char)0x05,(char)0x02,(char)0x00,(char)0x02};
nRet = send(m_socClientTCP_UdpAssociate,reqNego,4,0);
if( nRet==SOCKET_ERROR
{
DWORD dwError = WSAGetLastError();
if (dwError!=WSAEWOULDBLOCK) return NCM_E_WM_CREATE_PROXYREQUESTFAILED;
}

// 接收协商的响应
fd_set fdread; FD_ZERO(&fdread);
FD_SET(m_socClientTCP_UdpAssociate,&fdread);
if((nRet=select(0,&fdread,NULL,NULL,NULL))==SOCKET_ERROR) return NCM_E_WM_CREATE_PROXYCONNECTFAILED;
char resNego[2]={0};
int nRcvd=0,nCount=0;
if(FD_ISSET(m_socClientTCP_UdpAssociate,&fdread))
{
nRcvd = recv(m_socClientTCP_UdpAssociate, (char*)resNego+nRcvd, 2,0);
if(nRcvd==SOCKET_ERROR) return NCM_E_WM_CREATE_PROXYCONNECTFAILED;
}
if(resNego[0]!=0x05 || (resNego[1]!=0x00 && resNego[1]!=0x02)) return NCM_E_WM_CREATE_PROXYCONNECTFAILED;

// 看是否需要密码验证
if(resNego[1]==0x02)
{
// 需要密码验证
char reqAuth[513]; memset(reqAuth,0,513);
BYTE byLenUser = (BYTE)strlen(m_szProxyUserName);
BYTE byLenPswd = (BYTE)strlen(m_szProxyPassword);
reqAuth[0]=0x01;
reqAuth[1]=byLenUser;
sprintf(&reqAuth[2],"%s",m_szProxyUserName);
reqAuth[2+byLenUser]=byLenPswd;
sprintf(&reqAuth[3+byLenUser],"%s",m_szProxyPassword);
//Send authentication info
int len = (int)byLenUser + (int)byLenPswd + 3;
int ret=send(m_socClientTCP_UdpAssociate,(const char*)reqAuth,len,0);
if (ret==SOCKET_ERROR) if (GetLastError()!=WSAEWOULDBLOCK) return NCM_E_WM_CREATE_PROXYREQUESTFAILED;

//Now : Response to the auth request
char resAuth[2]={'\0'};
int nRcvd=0,nCount=0;
do{
ret = recv(m_socClientTCP_UdpAssociate,resAuth+nRcvd,2-nRcvd,0);
if(ret==SOCKET_ERROR){return NC_E_PROXY_RECEIVE|WSAGetLastError();}
nRcvd += nRet;
}
while((nRcvd!=2)&&(++nCount<1000));
if(nCount>=1000){return NC_E_PROXY_RECEIVE}
if (resAuth[1]!=0) return NEM_E_WM_CREATE_PROXYAUTHFAILED;
// 密码验证通过了
}

// 开始发送向目标服务器的连接请求,其中DST.ADDR是目标服务器的地址,DST.PORT是目标服务器的UDP端口
char reqSubNego[10]={(char)0x05,(char)0x03,(char)0x00,(char)0x01,(char)0x00,(char)0x00,(char)0x00,(char)0x00,(char)0x00,(char)0x00};
*(unsigned long*)&reqSubNego[4] =saiServerUDP.sin_addr.S_un.S_addr; // cmd: DEST.addr
*(unsigned short*)&reqSubNego[8]=saiServerUDP.sin_port; // cmd: DEST.port in network octet order
nRet=send(m_socClientTCP_UdpAssociate,(const char*)reqSubNego,10,0);
if (nRet==SOCKET_ERROR) return NEM_E_WM_CREATE_PROXYREQFAILED;

// 接收响应信息
int nRecvCount = 0;
int nRecvBufferLen = 10;
char szRecvBuf[10];
nRet = 0;
if(FD_ISSET(m_socClientTCP_UdpAssociate,&fdread))
{
int nRcvd=0,nCount=0;
do{
nRet = recv(m_socClientTCP_UdpAssociate,(char*)szRecvBuf+nRcvd,10-nRcvd,0);
if(nRet==SOCKET_ERROR){return NC_E_PROXY_RECEIVE|WSAGetLastError();}
nRcvd += nRet;
}
while((nRcvd!=10)&&(++nCount<1000));
if(nCount>=1000){return NC_E_PROXY_RECEIVE;}
if (szRecvBuf[0]!=0x05||szRecvBuf[1]!=0x00){return NC_E_PROXY_PROTOCOL_VERSION_SUB;}
}
else
{
return NCM_E_WM_CREATE_PROXYREQUESTFAILED;
}

// 代理服务器绑定udp地址BND.ADR,一般代理服务器都是多宿主机器,因此这个绑定地址是局域网地址,代理服务器绑定udp端口BND.PORT
// m_ulProxyUDPAddr 代理绑定地址
// m_usUDPAssociatePort 代理绑定端口
memmove(&m_ulProxyUDPAddr,&szRecvBuf[4],4);
memmove(&m_usUDPAssociatePort,&szRecvBuf[8],2);

m_bUDPAssociated = TRUE;
// 至此,得到了代理绑定的地址和端口,客户端就可以通过它来收发UDP数据报了


// 客户端收发实例
// 首先创建数据报套接字,绑定套接字,得到本地数据报套接字地址,端口
SOCKET m_socClientUDP=WSASocket(AF_INET,SOCK_DGRAM,0,NULL,0,WSA_FLAG_OVERLAPPED);
SOCKADDR_IN saiLocal;
memset(&saiLocal,0,sizeof(saiLocal));
saiLocal.sin_family = AF_INET;
saiLocal.sin_port = 0;
saiLocal.sin_addr.S_un.S_addr = INADDR_ANY;
// 绑定本地udp套接字地址,地址+端口由系统决定
if (bind(m_socClientUDP, (SOCKADDR *)&saiLocal, sizeof(saiLocal) == SOCKET_ERROR)
getsockname(m_socClientUDP, (sockaddr*)&saiLocal, &len);
// m_ulHostAddr 本机绑定地址
// m_usHostPortUdp 本机绑定端口
m_ulHostAddr = saiLocal.sin_addr.S_un.S_addr;
m_usHostPortUdp = saiLocal.sin_port;

// 按照格式,发送数据
SOCKADDR_IN saiProxy;
memset(&saiProxy,0,sizeof(saiProxy));
saiProxy.sin_family = AF_INET;
saiProxy.sin_addr.S_un.S_addr = m_ulProxyUDPAddr; // 代理绑定的udp地址
saiProxy.sin_port = m_usUDPAssociatePort; // 代理绑定的udp端口

// 每个UDP包必须携带如下所述的头:
+----+------+------+----------+----------+----------+
|RSV | FRAG | ATYP | DST.ADDR | DST.PORT | DATA |
+----+------+------+----------+----------+----------+
| 2 | 1 | 1 | Variable | 2 | Variable |
+----+------+------+----------+----------+----------+
// 其中 ATYP==0x01 表示采用 IPV4 地址,那么头长度就是10,DST.ADDR并不是服务器地址,而是本机绑定地址,DST.PORT是本机绑定端口
char buf[10+2]={'0x00','0x00','0x00','0x01','0xff'};
memmove(&buf[4],&m_ulHostAddr,4);
*(unsigned short*)&buf[8]=m_usHostPortUDP;
int nRet = sendto(m_socClientUDP,buf,12,0,(SOCKADDR*)&saiProxy,sizeof(saiProxy));

// 接收数据
int nLen = sizeof(saiProxy);
char buf=new char[MAX_UDPLEN];
nRet = recvfrom(m_socClientUDP,buf,MAX_UDPLEN,0,(SOCKADDR *)&saiProxy,&nLen);
if(nRet==SOCKET_ERROR) return SOCKET_ERROR;
BYTE flag=0xff;
if(memcmp(&buf[0],&flag,1)==0) return SOCKET_ERROR;
BYTE byProxyHead[20];
byProxyHead[0]=byProxyHead[1]=byProxyHead[2]=0;
byProxyHead[3]=1;
*(unsigned long*)&byProxyHead[4] = saiServerUDP.sin_addr.S_un.S_addr;
*(unsigned short*)&