代理服务器不加载图像

Proxy server does not load images

我正在尝试使用 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 作为浏览器。 任何想法为什么? 这也是制作代理服务器的最佳方式吗?还有其他方法吗?

经过一些测试,我编写了自己的代码。

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 请求。这由双回车 return 和换行符 \r\n\r\n 结束。一旦发生这种情况,我就会尝试使用 Linq 语句从请求中解析原始主机。我打开自己的服务器套接字,并使用异步回调。基本上,您需要将来自代理启动器的所有内容写入 HTTP-Server,并且 HTTP-Server 发回的所有内容也需要推回到原始客户端。这就是我设置自己的状态对象的原因,它只保存传入的客户端和连接到原始 HTTP 服务器的套接字。因此,可以进行通信,我充当代理服务器。

这是所有连接正确的屏幕截图:

这个代理服务器远非完美,但基本概念应该是清楚的。 This给了我一些灵感。

您在二进制图像数据上使用了流读取器,这将不起作用。并非每个二进制文件都是有效的 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();
}