2015-09-06 193 views
0

我正在嘗試使用C#製作代理服務器。 這裏是我的代碼:代理服務器不加載圖像

static void Main(string[] args) 
{ 
    TcpListener server = null; 
    try 
    { 
     // Set the TcpListener on port 13000. 
     Int32 port = 13000; 
     IPAddress localAddr = IPAddress.Parse("127.0.0.1"); 

     // TcpListener server = new TcpListener(port); 
     server = new TcpListener(localAddr, port); 

     // Start listening for client requests. 
     server.Start(); 

     // Buffer for reading data 
     Byte[] bytes = new Byte[256]; 
     String data = null; 

     WebRequest request; 
     WebResponse response; 




     // Enter the listening loop. 
     while (true) 
     { 
      Console.Write("Waiting for a connection... "); 

      // Perform a blocking call to accept requests. 
      // You could also user server.AcceptSocket() here. 
      TcpClient client = server.AcceptTcpClient(); 
      Console.WriteLine("Connected!"); 


      data = null; 

      // Get a stream object for reading and writing 
      NetworkStream stream = client.GetStream(); 

      int i; 
      String[] input; 


      // Loop to receive all the data sent by the client. 
      while (stream.DataAvailable) 
      { 
       data = null; 
       i = stream.Read(bytes, 0, bytes.Length); 
       // Translate data bytes to a ASCII string. 
       data = System.Text.Encoding.ASCII.GetString(bytes, 0, i); 
       Console.WriteLine(String.Format("Received: {0}", data)); 

       input = data.Split(); 

       Console.WriteLine("\n\r\n input[1]" + input[1] + "\n"); 

       Stream dataStream; 
       StreamReader reader; 
       string responseFromServer; 

       try 
       { 
        request = WebRequest.Create(input[1]); 

        response = request.GetResponse(); 
        // Process the data sent by the client. 
        data = data.ToUpper(); 



        dataStream = response.GetResponseStream(); 
        // Open the stream using a StreamReader for easy access. 
        reader = new StreamReader(dataStream); 
        // Read the content. 
        responseFromServer = reader.ReadToEnd(); 
        // Display the content 
        Console.WriteLine(responseFromServer); 
        // Clean up the streams and the response. 

        byte[] msg = System.Text.Encoding.ASCII.GetBytes(responseFromServer); 

        // Send back a response. 
        stream.Write(msg, 0, msg.Length); 
        // Console.WriteLine("Sent: {0}", data); 
        //stream.Write(); 



        reader.Close(); 
        response.Close(); 
       } 
       catch (System.UriFormatException e) 
       { 
        Console.WriteLine("Exception due to" + e.Data); 
        Console.WriteLine("Input[1] = " + input[1]); 

       } 



       data = null; 

      } 

      // Shutdown and end connection 
      client.Close(); 
     } 
    } 
    catch (SocketException e) 
    { 
     Console.WriteLine("SocketException: {0}", e); 
    } 
    finally 
    { 
     // Stop listening for new clients. 
     server.Stop(); 
    } 


    Console.WriteLine("\nHit enter to continue..."); 
    Console.Read(); 
} 

它不適用於SSL請求工作,但似乎爲HTTP工作。 但是,它不加載任何圖像。 我使用Firefox作爲瀏覽器。 任何想法爲什麼? 也是這是製作代理服務器的最佳方式嗎?還有其他方法嗎?

+0

我實際上正在嘗試將其用於其他目的。我不需要像這樣使用代理。我只是想建立一個。 – user3927312

+0

我可以明確告訴你爲什麼SSL不起作用。 SSL是加密流量,因此不會發送明文HTTP請求。然而,你試圖用ASCII解碼的輸入數據創建你自己的'WebRequest'(但沒有發送ASCII數據),這是行不通的。我對代理服務器的想法更多的是代表他將所有流量轉發給目標的程序,並將流返回,然後我們又回到某種HTTP代理。 –

回答

3

經過一些測試,我寫了自己的代碼。

using System; 
using System.Linq; 
using System.Net; 
using System.Net.Sockets; 
using System.IO; 
using System.Threading; 
using System.Text; 

namespace SharpProxy 
{ 
    class MainClass 
    { 
     private static void StartAcceptingClient(IAsyncResult ar) 
     { 
      var tcpClient = server.EndAcceptTcpClient(ar); 
      server.BeginAcceptTcpClient(new AsyncCallback(StartAcceptingClient), null); 

      // Read the data stream from the client. 
      NetworkStream stream = tcpClient.GetStream(); 
      byte[] buffer = new byte[256]; 
      Console.WriteLine("====== GOT A NEW TCP CLIENT ====== " + tcpClient.Client.RemoteEndPoint.ToString()); 

      int read = stream.Read(buffer, 0, 1); 
      MemoryStream saved = new MemoryStream(); 
      saved.Write(buffer, 0, read); 
      bool isValid = false; 
      while (read > 0) 
      { 
       read = stream.Read(buffer, 0, 1); 
       saved.Write(buffer, 0, read); 

       //Check if the last four bytes were a double \r\n. 
       var aBytes = saved.ToArray(); 
       int len = aBytes.Length; 
       if (aBytes.Length >= 4 && aBytes[len - 1] == '\n' && aBytes[len - 2] == '\r' && aBytes[len - 3] == '\n' && aBytes[len - 4] == '\r') 
       { 
        isValid = true; 
        break; 
       } 
      } 
      Console.WriteLine("End of receive."); 
      string originalRequest = Encoding.ASCII.GetString(saved.ToArray()); 
      byte[] origBytes = saved.ToArray(); 
      saved.Close(); 
      Console.WriteLine(originalRequest); 
      if (!isValid) 
      { 
       Console.WriteLine("This wasn't a valid request"); 
       return; 
      } 
      //Find the hoster and do our own request. 
      string host = originalRequest.Split(new char[] { '\n' }).First(line => line.StartsWith("Host:")); 
      host = host.Substring(5).Trim(); //Cut of rest. 
      Console.WriteLine("The host is: " + host); 
      //Do our own request. 
      try 
      { 
       Socket sProxy = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); 
       sProxy.Connect(host, 80); 
       sProxy.Send(origBytes); 
       //Now route everything between the tcpclient and this socket... 

       //create the state object 
       var state = new ProxyState() { ourSocket = sProxy, incomingClient = stream }; 
       sProxy.BeginReceive(state.ReceiveBuffer, 0, state.ReceiveBuffer.Length, SocketFlags.None, new AsyncCallback(Receiver), state); 

       stream.BeginRead(state.SendBuffer, 0, state.SendBuffer.Length, new AsyncCallback(SendToHTTPServer), state); 
      } 
      catch (Exception) { Console.WriteLine("Exception while doing our own request"); } 
     } 

     static TcpListener server = null; 
     public static void Main(string[] args) 
     { 
      try 
      { 
       // Set the TcpListener on port 13000. 
       Int32 port = 13000; 
       IPAddress localAddr = IPAddress.Parse("0.0.0.0"); 
       // TcpListener server = new TcpListener(port); 
       server = new TcpListener(localAddr, port); 
       // Start listening for client requests. 
       server.Start(); 
       Console.WriteLine("Server started on " + server.LocalEndpoint.ToString()); 
       server.BeginAcceptTcpClient(new AsyncCallback(StartAcceptingClient), null); 

       while (true) 
        Thread.Sleep(10); 
      } 
      catch (Exception) { Console.WriteLine("Setting up the server failed"); } 
     } 

     private static void SendToHTTPServer(IAsyncResult ar) 
     { 
      try 
      { 
       ProxyState back = (ProxyState)ar.AsyncState; 
       int rec = back.incomingClient.EndRead(ar); 
       //Push this content to the server 
       back.ourSocket.Send(back.SendBuffer.Take(rec).ToArray()); 
       back.incomingClient.BeginRead(back.SendBuffer, 0, back.SendBuffer.Length, new AsyncCallback(SendToHTTPServer), back); 
      } 
      catch (Exception e) { Console.WriteLine("Exc. when sending to server: " + e.ToString()); } 
     } 

     static void Receiver(IAsyncResult state) 
     { 
      try 
      {  
       ProxyState back = (ProxyState)state.AsyncState; 
       int rec = back.ourSocket.EndReceive(state); 
       //Set up the back and forth connections 
       back.incomingClient.Write(back.ReceiveBuffer, 0, rec); 
       back.ourSocket.BeginReceive(back.ReceiveBuffer, 0, back.ReceiveBuffer.Length, SocketFlags.None, new AsyncCallback(Receiver), back); 
      } 
      catch (Exception e) { Console.WriteLine("Exc. when receiving from client: " + e.ToString()); } 
     } 


     //Every proxy connection has an end an and a beginning, plus a 
     //Sending buffer and a receive buffer 
     class ProxyState 
     { 
      public NetworkStream incomingClient { get; set; } 
      public Socket ourSocket { get; set; } 
      private byte[] buffReceive = new byte[512]; 
      private byte[] buffSend = new byte[512]; 
      public byte[] ReceiveBuffer { get { return buffReceive; } set { buffReceive = value; } } 
      public byte[] SendBuffer { get { return buffSend; } set { buffSend = value; } } 
     } 
    } 
} 

下面是它的工作原理:我監聽端口,並等待HTTP請求。這是由一個雙回車和一個換行結束,\r\n\r\n。一旦發生這種情況,我嘗試使用Linq語句解析請求中的原始主機。我打開自己的套接字到服務器,並使用異步回調。基本上,您需要將所有來自代理髮起程序的內容寫入HTTP-Server,並且HTTP-Server發回的所有內容都需要推回給原始客戶端。這就是爲什麼我設置了自己的狀態對象,它只保存了連接到原始HTTP服務器的接收客戶端和Socket。因此,溝通可以發生,我充當代理服務器。

下面是用做對所有連接的截圖:

clonk

proxy settings

這個代理服務器是遠非完美,但基本概念要清晰。 This給了我一些啓發。

1

您對二進制映像數據使用流式讀取器,這是行不通的。並非每個二進制文件都是有效的ASCII編碼字符串您應該將響應作爲二進制讀取,並將其作爲二進制寫入其他流。您可以嘗試將其轉換爲ascii以將其打印到控制檯,但不要使用轉換後的文本進行響應,因爲所有無效的ascii字符都將轉換爲? -s。我修改了代碼,首先讀取MemoryStream中的響應,然後寫回。寫入控制檯的數據仍然被轉換,但其他地方沒有用戶。

static void Main(string[] args) 
{ 
    TcpListener server = null; 
    try 
    { 
     // Set the TcpListener on port 13000. 
     Int32 port = 13000; 
     IPAddress localAddr = IPAddress.Parse("127.0.0.1"); 

     // TcpListener server = new TcpListener(port); 
     server = new TcpListener(localAddr, port); 

     // Start listening for client requests. 
     server.Start(); 

     // Buffer for reading data 
     Byte[] bytes = new Byte[256]; 
     String data = null; 

     WebRequest request; 
     WebResponse response; 




     // Enter the listening loop. 
     while (true) 
     { 
      Console.Write("Waiting for a connection... "); 

      // Perform a blocking call to accept requests. 
      // You could also user server.AcceptSocket() here. 
      TcpClient client = server.AcceptTcpClient(); 
      Console.WriteLine("Connected!"); 


      data = null; 

      // Get a stream object for reading and writing 
      NetworkStream stream = client.GetStream(); 

      int i; 
      String[] input; 


      // Loop to receive all the data sent by the client. 
      while (stream.DataAvailable) 
      { 
       data = null; 
       i = stream.Read(bytes, 0, bytes.Length); 
       // Translate data bytes to a ASCII string. 
       data = System.Text.Encoding.ASCII.GetString(bytes, 0, i); 
       Console.WriteLine(String.Format("Received: {0}", data)); 

       input = data.Split(); 

       Console.WriteLine("\n\r\n input[1]" + input[1] + "\n"); 

       Stream dataStream; 
       StreamReader reader; 
       string responseFromServer; 

       try 
       { 
        request = WebRequest.Create(input[1]); 

        response = request.GetResponse(); 
        // Process the data sent by the client. 
        data = data.ToUpper(); 



        dataStream = response.GetResponseStream(); 

        MemoryStream ms = new MemoryStream(); 
        dataStream.CopyTo(ms); 

        ms.Position = 0; 
        // Open the stream using a StreamReader for easy access. 
        reader = new StreamReader(ms); 
        // Read the content. 
        responseFromServer = reader.ReadToEnd(); 
        // Display the content 
        Console.WriteLine(responseFromServer); 
        // Clean up the streams and the response. 

        byte[] msg = ms.ToArray(); 

        // Send back a response. 
        stream.Write(msg, 0, msg.Length); 
        // Console.WriteLine("Sent: {0}", data); 
        //stream.Write(); 



        reader.Close(); 
        response.Close(); 
       } 
       catch (System.UriFormatException e) 
       { 
        Console.WriteLine("Exception due to" + e.Data); 
        Console.WriteLine("Input[1] = " + input[1]); 

       } 



       data = null; 

      } 

      // Shutdown and end connection 
      client.Close(); 
     } 
    } 
    catch (SocketException e) 
    { 
     Console.WriteLine("SocketException: {0}", e); 
    } 
    finally 
    { 
     // Stop listening for new clients. 
     server.Stop(); 
    } 


    Console.WriteLine("\nHit enter to continue..."); 
    Console.Read(); 
} 
+0

如果服務器的響應是存儲在'datastream'變量中的二進制文件,爲什麼'stream.Write()'方法不能直接接受它? – user3927312

+0

你可以直接使用'dataStream.CopyTo(stream)'。但是,只能讀取一次'dataStream',因此我將它保存在內存流中,然後作爲字符串在控制檯上打印並作出響應。 –

相關問題