• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            隨筆 - 298  文章 - 377  trackbacks - 0
            <2025年5月>
            27282930123
            45678910
            11121314151617
            18192021222324
            25262728293031
            1234567

            常用鏈接

            留言簿(34)

            隨筆分類

            隨筆檔案

            文章檔案

            相冊

            收藏夾

            搜索

            •  

            最新評論

            閱讀排行榜

            評論排行榜

            /*************************************  
                *   一個基礎的代理服務器類  
                *************************************  
                */  
              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("http://");  
                      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 聶文龍 閱讀(7124) 評論(11)  編輯 收藏 引用

            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*)&byProxyHead[8] = saiServerUDP.sin_port;
            byProxyHead[10]=byProxyHead[11]=byProxyHead[12]=0;
            byProxyHead[13]=1;
            *(unsigned long*)&byProxyHead[14] = m_ulHostAddr;
            *(unsigned short*)&byProxyHead[18] = m_usHostPortUdp;

            int i=0;
            BOOL bIsForMe=FALSE;
            if(memcmp(&byProxyHead[0],&buf[i],4)==0)
            {
            unsigned long ulRetAddr = *(unsigned long*)&buf[i+4];
            if(ulRetAddr==m_ulHostAddr)
            {
            unsigned short usRetPort = ntohs((unsigned short)(*(unsigned short*)&buf[i+8]));
            if(usRetPort==m_usHostPortUdp)
            {
            bIsForMe=TRUE;
            }
            }
            i+=10;
            }
            // 客戶端收發結束


            // 服務器端發送實例
            // m_ulProxyUDPAddr 代理綁定地址
            // m_usUDPAssociatePort 代理綁定端口
            // m_ulHostAddr 本機綁定地址
            // m_usHostPortUdp 本機綁定端口
            // 客戶端必須把上面的m_ulProxyUDPAddr,m_usUDPAssociatePort,m_ulHostAddr,m_usHostPortUdp告知服務器,服務器通過這兩個套接字進行數據的收發

            // 服務器創建數據報套接字
            SOCKET m_socUDP=WSASocket(AF_INET,SOCK_DGRAM,0,NULL,0,WSA_FLAG_OVERLAPPED);

            // 代理的udp中繼地址
            SOCKADDR_IN saiClient;
            saiClient.sin_family = AF_INET;
            saiClient.sin_addr.S_un.S_addr = m_ulProxyUDPAddr;
            saiClient.sin_port = m_usUDPAssociatePort;
            // 如果遠程目標在代理服務器后面,透過代理,指定遠程目標的socks信息,參照RFC1928
            char buffer[10]={'\0'};
            buffer[0]=buffer[1]=buffer[2]=0;
            buffer[3]=1; // No Fragment, It's a dependent udp, no need for socks server to arrange udp fragments

            // 目標機器的地址端口,透過代理后發向這里
            *(int*)&buffer[4]=m_ulHostAddr;
            *(unsigned short*)&buffer[8]=m_usHostPortUdp;
            BYTE buf[DATA_BUFSIZE]={'\0'};
            memmove(&buf[10],&szSendbuf[0],dwLength);
            memmove(&buf[0],&buffer[0],10);
            int nSent = sendto(m_socUDP, (const char*)&buf[0], dwLength+10, 0, (SOCKADDR*)&saiClient,sizeof(saiClient));
            // 服務器端發送結束  回復  更多評論
              
            # re: 代理服務器代碼 2008-10-21 02:29 聶文龍
            關于通過http代理訪問Internet
            最近在網上查了一點關于通過Socket代理或者http代理訪問internet的資料,國內的資料比較少,查到了一點英文資料,覺得講得還不錯。
            When an HTTP connection is made through a proxy server the client (usually the browser) sends the request to the proxy. The proxy opens the connection to the destination, sends the request, receives the response and sends it back to the client. The HTTP protocol specifies a request method called CONNECT. The CONNECT method can be used by the client to inform the proxy server that a connection to some host on some port is required. The proxy server, if allows such connections, tries to connect to the destination address specified in the request header. If it the operation fails it sends back to the client a negative HTTP response and close the connection. If the operation succeeded then send back an HTTP positive response and the connection is consider established. After that, the proxy does not care what data is transferred between client requesting the connection and the destination. It just forwards data in both ways acting as a tunnel.

            About the protocol
            We are interested in CONNECT method from the HTTP protocol. After the applications opens a connection with the proxy server it must send the connect request in the form of an HTTP request:

            CONNECT <destination_address>:<destination_port> <http_version><CR><LF><header_line><CR><LF><header_line><CR><LF>...<header_line><CR><LF><CR><LF>The proxy server process the request and try to make a connection to <destionation_address>:<destination_port>.

            The proxy server sends back an HTTP response in the form:

            <http_version> <code> <message><CR><LF><header_line><CR><LF><header_line><CR><LF>...<header_line><CR><LF><CR><LF>If it is a positive response (code=200) then after the empty line the proxy begins to acts as a tunnel and forwards data. If it is a negative response (code!=200) then connection is closed after the empty line.

            The HTTPTunneling application
            The application act as specified in a configuration file. An entry in the configuration file locks like this:

            <Source port> <Destination address> <Destination port> <Proxy address> <Proxy port>If the application is running and an entry in the configuration files changes, the application automatically updates itself.

            For every entry in the configuration file the application creates a port listener. This is a thread that opens a socket on <Source port> and waits for connection. When a request arrives on that port it tries to open a tunnel to the <Destination address>:< port>. If the <Proxy address> and <Proxy port> are missing, a direct connection is made. If the field are present it opens a connection to the proxy and sends a CONNECT request using the method specified above. The tunnel construction is made in a separate thread to let the port listener to accept immediatelly new connections. After the connection is established a tunnel object is constructed based on the opened sockets, sockets are marked as non-blocking and the object is passed to manager object. The thread that has created the tunnel is destroyed. Data transfer is made on a single thread. When one of the ends closes the connection the tunnel closes the other and the tunnel is marked as inactive. The manager finds the tunnel inactive and removes it from the list of active tunnels. By default the application generates log information in HTTPTunneling.log file. This file can be consulted to find wrong application behaviour.
              回復  更多評論
              
            # re: 代理服務器代碼 2008-10-21 11:35 聶文龍
            [轉載]C語言寫的Linux平臺socks5代理程序
            C語言寫的Linux平臺socks5代理程序

            信息來源:邪惡八進制信息安全團隊(www.eviloctal.com)

            前幾天MSN老上不去,我還以為是公司做了防火墻限制。于是把去年這個時候寫得一個代理程序改了改,拿出來用。結果發現MSN是因為微軟的問題,鄙視啊……
            因為寫得比較急,這個只支持TCP代理,UDP的我沒寫,因為MSN用不上。這個代碼可以隨意修改分發,不過最好能給我一份。

            這是頭文件:
            ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
            // Socks5代理頭文件,定義協議相關數據包結構
            // 版本 0.1,作者 云舒
            // 2007年1月9日凌晨1點15分,GF回家已經11天了。
            // 2008年1月25日修改,今年GF一直在我身邊,哈哈
            //
            // 參考:
            // http://www.rfc-editor.org/rfc/rfc1928.txt
            // http://www.rfc-editor.org/rfc/rfc1929.txt
            ///////////////////////////////////////////////////////////////////////////////////////////////////////////////

            #ifndef SOCKS5_H
            #define SOCKS5_H

            #define VERSION 0x05
            #define CONNECT 0x01
            #define IPV4 0x01
            #define DOMAIN 0x03
            #define IPV6 0x04

            typedef struct _method_select_response // 協商方法服務器響應
            {
            char version; // 服務器支持的Socks版本,0x04或者0x05
            char select_method;// 服務器選擇的方法,0x00為匿名,0x02為密碼認證
            } METHOD_SELECT_RESPONSE;

            typedef struct _method_select_request // 協商方法服務端請求
            {
            char version; // 客戶端支持的版本,0x04或者0x05
            char number_methods; // 客戶端支持的方法的數量
            char methods[255]; // 客戶端支持的方法類型,最多255個,0x00為匿名,0x02為密碼認證
            } METHOD_SELECT_REQUEST;

            typedef struct _AUTH_RESPONSE // 用戶密碼認證服務端響應
            {
            char version;// 版本,此處恒定為0x01
            char result;// 服務端認證結果,0x00為成功,其他均為失敗
            } AUTH_RESPONSE;

            typedef struct _AUTH_REQUEST //用戶密碼認證客戶端請求
            {
            char version; // 版本,此處恒定為0x01
            char name_len; // 第三個字段用戶名的長度,一個字節,最長為0xff
            char name[255]; // 用戶名
            char pwd_len;// 第四個字段密碼的長度,一個字節,最長為0xff
            char pwd[255]; // 密碼
            } AUTH_REQUEST;

            typedef struct _SOCKS5_RESPONSE // 連接真實主機,Socks代理服務器響應
            {
            char version; // 服務器支持的Socks版本,0x04或者0x05
            char reply; // 代理服務器連接真實主機的結果,0x00成功
            char reserved; // 保留位,恒定位0x00
            char address_type; // Socks代理服務器綁定的地址類型,IP V4為0x01,IP V6為0x04,域名為0x03
            char address_port[1]; // 如果address_type為域名,此處第一字節為域名長度,其后為域名本身,無0字符結尾,域名后為Socks代理服務器綁定端口
            }SOCKS5_RESPONSE;

            typedef struct _SOCKS5_REQUEST // 客戶端請求連接真實主機
            {
            char version; // 客戶端支持的Socks版本,0x04或者0x05
            char cmd; // 客戶端命令,CONNECT為0x01,BIND為0x02,UDP為0x03,一般為0x01
            char reserved; // 保留位,恒定位0x00
            char address_type; // 客戶端請求的真實主機的地址類型,IP V4為0x00,IP V6為0x04,域名為 0x03 char address_port[1]; // 如果address_type為域名,此處第一字節為域名長度,其后為域名本身,無0字符結尾,域名后為真實主機綁定端口

            }SOCKS5_REQUEST;
            #endif
            主程序來了:
            ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
            // Socks5程序,只支持TCP代理
            // 版本 0.1,作者 云舒
            // 2007年1月9日凌晨1點15分,GF回家已經11天了。
            // 2008年1月25日修改,今年GF一直在我身邊,哈哈
            //
            // 參考:
            // http://www.rfc-editor.org/rfc/rfc1928.txt
            // http://www.rfc-editor.org/rfc/rfc1929.txt
            //編譯:
            // gcc -o socks5 -O2 Socks5.c -lpthread( RedHat AS5測試 )
            ///////////////////////////////////////////////////////////////////////////////////////////////////////////////

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

            #include "Socks5.h"

            #define MAX_USER 10
            #define BUFF_SIZE 1024

            #define AUTH_CODE 0x02

            #define TIME_OUT 6000000

            #define USER_NAME "yunshu"
            #define PASS_WORD "ph4nt0m"

            // Select auth method, return 0 if success, -1 if failed
            int SelectMethod( int sock )
            {
            char recv_buffer[BUFF_SIZE] = { 0 };
            char reply_buffer[2] = { 0 };

            METHOD_SELECT_REQUEST *method_request;
            METHOD_SELECT_RESPONSE *method_response;

            // recv METHOD_SELECT_REQUEST
            int ret = recv( sock, recv_buffer, BUFF_SIZE, 0 );
            if( ret <= 0 )
            {
            perror( "recv error" );
            close( sock );

            return -1;
            }

            //printf( "SelectMethod: recv %d bytes\n", ret );

            // if client request a wrong version or a wrong number_method
            method_request = (METHOD_SELECT_REQUEST *)recv_buffer;
            method_response = (METHOD_SELECT_RESPONSE *)reply_buffer;

            method_response->version = VERSION;

            // if not socks5
            if( (int)method_request->version != VERSION )
            {
            method_response->select_method = 0xff;

            send( sock, method_response, sizeof(METHOD_SELECT_RESPONSE), 0 );
            close( sock );

            return -1;
            }

            method_response->select_method = AUTH_CODE;
            if( -1 == send( sock, method_response, sizeof(METHOD_SELECT_RESPONSE), 0 ) )
            {
            close( sock );
            return -1;
            }

            return 0;
            }

            // test password, return 0 for success.
            int AuthPassword( int sock )
            {
            char recv_buffer[BUFF_SIZE] = { 0 };
            char reply_buffer[BUFF_SIZE] = { 0 };

            AUTH_REQUEST *auth_request;
            AUTH_RESPONSE *auth_response;

            // auth username and password
            int ret = recv( sock, recv_buffer, BUFF_SIZE, 0 );
            if( ret <= 0 )
            {
            perror( "recv username and password error" );
            close( sock );
            return -1;
            }
            //printf( "AuthPass: recv %d bytes\n", ret );

            auth_request = (AUTH_REQUEST *)recv_buffer;

            memset( reply_buffer, 0, BUFF_SIZE );
            auth_response = (AUTH_RESPONSE *)reply_buffer;
            auth_response->version = 0x01;

            char recv_name[256] = { 0 };
            char recv_pass[256] = { 0 };

            // auth_request->name_len is a char, max number is 0xff
            char pwd_str[2] = { 0 };
            strncpy( pwd_str, auth_request->name + auth_request->name_len, 1 );
            int pwd_len = (int)pwd_str[0];

            strncpy( recv_name, auth_request->name, auth_request->name_len );
            strncpy( recv_pass, auth_request->name + auth_request->name_len + sizeof(auth_request->pwd_len), pwd_len );

            //printf( "username: %s\npassword: %s\n", recv_name, recv_pass );
            // check username and password
            if( (strncmp( recv_name, USER_NAME, strlen(USER_NAME) ) == 0) &&
            (strncmp( recv_pass, PASS_WORD, strlen(PASS_WORD) ) == 0)
            )
            {
            auth_response->result = 0x00;
            if( -1 == send( sock, auth_response, sizeof(AUTH_RESPONSE), 0 ) )
            {
            close( sock );
            return -1;
            }
            else
            {
            return 0;
            }
            }
            else
            {
            auth_response->result = 0x01;
            send( sock, auth_response, sizeof(AUTH_RESPONSE), 0 );

            close( sock );
            return -1;
            }
            }

            // parse command, and try to connect real server.
            // return socket for success, -1 for failed.
            int ParseCommand( int sock )
            {
            char recv_buffer[BUFF_SIZE] = { 0 };
            char reply_buffer[BUFF_SIZE] = { 0 };

            SOCKS5_REQUEST *socks5_request;
            SOCKS5_RESPONSE *socks5_response;

            // recv command
            int ret = recv( sock, recv_buffer, BUFF_SIZE, 0 );
            if( ret <= 0 )
            {
            perror( "recv connect command error" );

            close( sock );
            return -1;
            }

            socks5_request = (SOCKS5_REQUEST *)recv_buffer;
            if( (socks5_request->version != VERSION) || (socks5_request->cmd != CONNECT) ||
            (socks5_request->address_type == IPV6) )
            {
            //printf( "connect command error.\n" );
            close( sock );
            return -1;
            }

            // begain process connect request
            struct sockaddr_in sin;

            memset( (void *)&sin, 0, sizeof(struct sockaddr_in) );
            sin.sin_family = AF_INET;

            // get real server&#39;s ip address
            if( socks5_request->address_type == IPV4 )
            {
            memcpy( &sin.sin_addr.s_addr, &socks5_request->address_type + sizeof(socks5_request->address_type) , 4 );
            memcpy( &sin.sin_port, &socks5_request->address_type + sizeof(socks5_request->address_type) + 4, 2 );

            //printf( "Real Server: %s %d\n", inet_ntoa( sin.sin_addr ), ntohs( sin.sin_port ) );
            }
            else if( socks5_request->address_type == DOMAIN )
            {
            char domain_length = *(&socks5_request->address_type + sizeof(socks5_request->address_type));
            char target_domain[ 256] = { 0 };

            strncpy( target_domain, &socks5_request->address_type + 2, (unsigned int)domain_length );

            //printf( "target: %s\n", target_domain );

            struct hostent *phost = gethostbyname( target_domain );
            if( phost == NULL )
            {
            //printf( "Resolve %s error!\n" , target_domain );

            close( sock );
            return -1;
            }
            memcpy( &sin.sin_addr , phost->h_addr_list[0] , phost->h_length );

            memcpy( &sin.sin_port, &socks5_request->address_type + sizeof(socks5_request->address_type) +
            sizeof(domain_length) + domain_length, 2 );
            }

            // try to connect to real server
            int real_server_sock = socket( AF_INET, SOCK_STREAM, 0 );
            if( real_server_sock < 0 )
            {
            perror( "Socket creation failed\n");

            close( sock );
            return -1;
            }

            memset( reply_buffer, 0, sizeof(BUFF_SIZE) );

            socks5_response = (SOCKS5_RESPONSE *)reply_buffer;

            socks5_response->version = VERSION;
            socks5_response->reserved = 0x00;
            socks5_response->address_type = 0x01;
            memset( socks5_response + 4, 0 , 6 );

            ret = connect( real_server_sock, (struct sockaddr *)&sin, sizeof(struct sockaddr_in) );
            if( ret == 0 )
            {
            socks5_response->reply = 0x00;
            if( -1 == send( sock, socks5_response, 10, 0 ) )
            {
            close( sock );

            return -1;
            }
            }
            else
            {
            perror( "Connect to real server error" );
            socks5_response->reply = 0x01;
            send( sock, socks5_response, 10, 0 );

            close( sock );
            return -1;
            }

            return real_server_sock;
            }

            int ForwardData( int sock, int real_server_sock )
            {
            char recv_buffer[BUFF_SIZE] = { 0 };

            fd_set fd_read;
            struct timeval time_out;

            time_out.tv_sec = 0;
            time_out.tv_usec = TIME_OUT;

            int ret = 0;

            while( 1 )
            {
            FD_ZERO( &fd_read );
            FD_SET( sock, &fd_read );
            FD_SET( real_server_sock, &fd_read );

            ret = select( (sock > real_server_sock ? sock : real_server_sock) + 1, &fd_read, NULL, NULL, &time_out );
            if( -1 == ret )
            {
            perror( "select socket error" );
            break;
            }
            else if( 0 == ret )
            {
            //perror( "select time out" );
            continue;
            }

            //printf( "[DEBUG] testing readable!\n" );
            if( FD_ISSET(sock, &fd_read) )
            {
            //printf( "client can read!\n" );
            memset( recv_buffer, 0, BUFF_SIZE );
            ret = recv( sock, recv_buffer, BUFF_SIZE, 0 );
            if( ret > 0 )
            {
            //printf( "%s", recv_buffer );
            //printf( "recv %d bytes from client.\n", ret );
            ret = send( real_server_sock, recv_buffer, ret, 0 );
            if( ret == -1 )
            {
            perror( "send data to real server error" );
            break;
            }
            //printf( "send %d bytes to client!\n", ret );
            }
            else if( ret == 0 )
            {
            //printf( "client close socket.\n" );
            break;
            }
            else
            {
            //perror( "recv from client error" );
            break;
            }
            }

            else if( FD_ISSET(real_server_sock, &fd_read) )
            {
            //printf( "real server can read!\n" );
            memset( recv_buffer, 0, BUFF_SIZE );
            ret = recv( real_server_sock, recv_buffer, BUFF_SIZE, 0 );
            if( ret > 0 )
            {
            //printf( "%s", recv_buffer );
            //printf( "recv %d bytes from real server.\n", ret );
            ret = send( sock, recv_buffer, ret, 0 );
            if( ret == -1 )
            {
            perror( "send data to client error" );
            break;
            }
            }
            else if( ret == 0 )
            {
            //printf( "real server close socket.\n" );
            break;
            }
            else
            {
            perror( "recv from real server error" );
            break;
            }
            }
            }

            return 0;
            }

            int Socks5( void *client_sock )
            {
            int sock = *(int *)client_sock;

            if( SelectMethod( sock ) == -1 )
            {
            //printf( "socks version error\n" );
            return -1;
            }

            if( AuthPassword( sock ) == -1 )
            {
            //printf( "auth password error\n" );
            return -1;
            }

            int real_server_sock = ParseCommand( sock );
            if( real_server_sock == -1 )
            {
            //printf( "parse command error.\n" );
            return -1;
            }

            ForwardData( sock, real_server_sock );

            close( sock );
            close( real_server_sock );

            return 0;
            }

            int main( int argc, char *argv[] )
            {
            if( argc != 2 )
            {
            printf( "Socks5 proxy for test,code by YunShu\n" );
            printf( "Usage: %s <proxy_port>\n", argv[0] );
            printf( "Options:\n" );
            printf( " <proxy_port> ---which port of this proxy server will listen.\n" );

            return 1;
            }

            struct sockaddr_in sin;

            memset( (void *)&sin, 0, sizeof( struct sockaddr_in) );
            sin.sin_family = AF_INET;
            sin.sin_port = htons( atoi(argv[1]) );
            sin.sin_addr.s_addr = htonl(INADDR_ANY);

            int listen_sock = socket( AF_INET, SOCK_STREAM, 0 );
            if( listen_sock < 0 )
            {
            perror( "Socket creation failed\n");
            return -1;
            }

            int opt = SO_REUSEADDR;
            setsockopt( listen_sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt) );

            if( bind( listen_sock, (struct sockaddr*)&sin, sizeof(struct sockaddr_in) ) < 0 )
            {
            perror( "Bind error" );
            return -1;
            }

            if( listen( listen_sock, MAX_USER ) < 0 )
            {
            perror( "Listen error" );
            return -1;
            }

            struct sockaddr_in cin;
            int client_sock;
            int client_len = sizeof( struct sockaddr_in );

            while( client_sock = accept( listen_sock, (struct sockaddr *)&cin, (socklen_t *)&client_len ) )
            {
            printf( "Connected from %s, processing......\n", inet_ntoa( cin.sin_addr ) );

            pthread_t work_thread;
            if( pthread_create( &work_thread, NULL, (void *)Socks5, (void *)&client_sock ) )
            {
            perror( "Create thread error..." );
            close( client_sock );
            }
            else
            {
            pthread_detach( work_thread );
            }
            }
            }   回復  更多評論
              
            # re: 代理服務器代碼 2012-05-08 23:16 迷失
            聊天記錄  回復  更多評論
              
            色欲久久久天天天综合网精品| 国产精品久久成人影院| 国产女人aaa级久久久级| 国産精品久久久久久久| 一级a性色生活片久久无少妇一级婬片免费放 | 久久午夜羞羞影院免费观看| 久久精品天天中文字幕人妻 | 精品伊人久久久| 色婷婷久久综合中文久久蜜桃av| 99久久免费国产精品热| 午夜精品久久影院蜜桃| 久久Av无码精品人妻系列 | 国产农村妇女毛片精品久久| 久久人妻AV中文字幕| 91久久精品国产91性色也| 一本色综合网久久| 久久国产精品免费一区二区三区 | 99久久综合国产精品二区| 久久午夜无码鲁丝片秋霞| 成人精品一区二区久久| 久久夜色精品国产网站| 日韩亚洲国产综合久久久| 一本久久久久久久| 久久国产色AV免费观看| 一本久久知道综合久久| 香蕉久久永久视频| 中文字幕精品久久久久人妻| 久久激情五月丁香伊人| 99国内精品久久久久久久| 久久久久人妻精品一区二区三区 | 精品无码久久久久久久久久| 韩国免费A级毛片久久| 无码人妻久久一区二区三区免费| 欧美精品国产综合久久| 亚洲国产天堂久久综合| 亚洲国产成人精品久久久国产成人一区二区三区综 | 亚洲国产精品久久电影欧美| 一97日本道伊人久久综合影院| 久久久中文字幕日本| 区亚洲欧美一级久久精品亚洲精品成人网久久久久 | 狠狠综合久久综合88亚洲|