2012-08-14 28 views
1

我已經使用System.Net和System.Net.Sockets的同步方法和類在C#中編寫了一個簡單的代理服務器。大部分的事情都完成了,除了一個小故障。簡單代理服務器故障排除

當我從代理客戶端(比如說www.google.com)瀏覽一個url時,它會打開。當我做一個關鍵字搜索,太好了。但是,當我點擊搜索結果時,客戶再次在屏幕上看到google.com主頁!但是,客戶端瀏覽器url欄仍然顯示單擊的搜索結果url。 也許這是發生,因爲谷歌結果頁面不提供直接鏈接到結果url,而是一個鏈接到谷歌本身,我認爲我的代碼中的繼電器邏輯無法處理。你能幫我解決這個問題嗎?我的代碼如下: (該ThreadHandleClient()方法是最重要的一個是處理所有的客戶端請求和繼電器請求和響應)

public void Start(IPAddress ip, int port) 
    { 
     try 
     { 
      TcpListener listener = new TcpListener(ip, port); 
      listener.Start(100); 
      while (!stopFlag) 
      { 
       Socket client = listener.AcceptSocket(); 
       IPEndPoint rep = (IPEndPoint)client.RemoteEndPoint; 
       Thread th = new Thread(ThreadHandleClient); 
       th.Start(client); 
      } 

      listener.Stop(); 
     } 
     catch (Exception ex) 
     { 
      Debug.Print("START: " + ex.Message); 
     } 
    } 

    public void Stop() 
    { 
     stopFlag = true;  
    } 

    public void ThreadHandleClient(object o) 
    { 
     try 
     { 
      Socket client = (Socket)o; 
      Debug.Print("lingerstate=" + client.LingerState.Enabled.ToString() + " timeout=" + client.LingerState.LingerTime.ToString()); 
      NetworkStream ns = new NetworkStream(client); 
      //RECEIVE CLIENT DATA 
      byte[] buffer = new byte[2048]; 
      int rec = 0, sent = 0, transferred = 0, rport = 0; 
      string data = ""; 
      do 
      { 
       rec = ns.Read(buffer, 0, buffer.Length); 
       data += Encoding.ASCII.GetString(buffer, 0, rec); 
      } while (rec == buffer.Length); 

      //PARSE DESTINATION AND SEND REQUEST 
      string line = data.Replace("\r\n", "\n").Split(new string[] { "\n" }, StringSplitOptions.None)[0]; 
      Uri uri = new Uri(line.Split(new string[] { " " }, StringSplitOptions.None)[1]); 
      Debug.Print("CLIENT REQUEST RECEIVED: " + uri.OriginalString); 
      if (uri.Scheme == "https") 
      { 
       rport = 443; 
       Debug.Print("HTTPS - 443"); 

       //rq = HttpVersion + " 200 Connection established\r\nProxy-Agent: Prahlad`s Proxy Server\r\n\r\n"; 
       //ClientSocket.BeginSend(Encoding.ASCII.GetBytes(rq), 0, rq.Length, SocketFlags.None, new AsyncCallback(this.OnOkSent), ClientSocket); 
      } 
      else 
      { 
       rport = 80; 
       Debug.Print("HTTP - 443"); 
      } 
      IPHostEntry rh = Dns.GetHostEntry(uri.Host); 
      Socket webserver = new Socket(rh.AddressList[0].AddressFamily, SocketType.Stream, ProtocolType.IP); 
      webserver.Connect(new IPEndPoint(rh.AddressList[0], rport)); 
      byte[] databytes = Encoding.ASCII.GetBytes(data); 
      webserver.Send(databytes, databytes.Length, SocketFlags.None); 
      Debug.Print("SENT TO SERVER. WILL NOW RELAY: " + data); 

      //START RELAY 
      buffer = new byte[2048]; 
      bool firstTime = true; 
      rec = 0; 
      data = ""; 
      do 
      { 
       transferred = 0; 
       do 
       { 
        if (webserver.Poll((firstTime ? 9000 : 2000) * 1000, SelectMode.SelectRead)) 
        { 
         rec = webserver.Receive(buffer, buffer.Length, SocketFlags.None); 
         Debug.Print("RECEIVED FROM WEBSERVER[" + rec.ToString() + "]: " + Encoding.ASCII.GetString(buffer, 0, rec)); 
         firstTime = false; 
         sent = client.Send(buffer, rec, SocketFlags.None); 
         Debug.Print("SENT TO CLIENT[" + sent.ToString() + "]: " + Encoding.ASCII.GetString(buffer, 0, rec)); 
         transferred += rec; 
        } 
        else 
        { 
         Debug.Print("No data polled from webserver"); 
        } 
       } while (rec == buffer.Length); 

       Debug.Print("loop-1 finished"); 

       //if (transferred == 0) 
       //  break; 

       //transferred = 0; 
       rec = 0; 
       do 
       { 
        if (client.Poll(1000 * 1000, SelectMode.SelectRead)) 
        { 
         rec = client.Receive(buffer, buffer.Length, SocketFlags.None); 
         Debug.Print("RECEIVED FROM CLIENT: " + Encoding.ASCII.GetString(buffer, 0, rec)); 

         sent = webserver.Send(buffer, rec, SocketFlags.None); 
         Debug.Print("SENT TO WEBSERVER[" + sent.ToString() + "]: " + Encoding.ASCII.GetString(buffer, 0, rec)); 
         transferred += rec; 
        } 
        else 
        { 
         Debug.Print("No data polled from client"); 
        } 
       } while (rec == buffer.Length); 
       Debug.Print("loop-2 finished"); 

      } while (transferred > 0); 
      Debug.Print("LOOP ENDS. EXITING THREAD"); 
      client.Close(); 
      webserver.Close(); 
     } 
     catch (Exception ex) 
     { 
      Debug.Print("Error occured: " + ex.Message); 
     } 
     finally { 
      Debug.Print("Client thread closed"); 
     } 
    } 

回答

0

一些試驗和錯誤之後,我找到了解決辦法,所以我」回答我自己的問題。我的中繼邏輯的問題是,它用於中繼兩種方式,即從webserver-> client和client-> webserver。 我意識到中繼第二部分可能會導致重定向出現問題,因爲在重定向時,頭部的url部分(「GET http://debian.org HTTP/1.1」)會突然改變,所以它會與正在中繼的Web服務器不同!例如,谷歌重定向指向debian.org,而代理服務器仍將傳遞來自google.com而不是debian.org的流量。 爲了避免這種情況,我刪除了第二個中繼部分(即client-> webserver)。如果客戶端發送新請求,最好在單獨的線程中處理,以便將其定向到正確的url主機。所以,我所要做的就是註釋掉我繼電器邏輯中的第二個內部迴路:

   //rec = 0; 
       //do 
       //{ 
       // if (client.Poll(3000 * 1000, SelectMode.SelectRead)) 
       // { 
       //  rec = client.Receive(buffer, buffer.Length, SocketFlags.None); 
       //  Debug.Print("RECEIVED FROM CLIENT: " + Encoding.ASCII.GetString(buffer, 0, rec)); 

       //  sent = webserver.Send(buffer, rec, SocketFlags.None); 
       //  Debug.Print("SENT TO WEBSERVER[" + sent.ToString() + "]: " + Encoding.ASCII.GetString(buffer, 0, rec)); 
       //  transferred += rec; 
       // } 
       // else 
       // { 
       //  Debug.Print("No data polled from client"); 
       // } 
       //} while (rec == buffer.Length); 
       //Debug.Print("loop-2 finished");