天天看點

簡單實作Http代理工具

本來意圖是想寫個工具放到伺服器裡代理一下上秋秋的。

沒想到N台(電信/聯通/移動)的伺服器都把端口全封了。

是以以下代碼是在本地測試代理網頁通路通過。

說下思路再上代碼及下載下傳:

其實一句話就是:産生兩個Soket,一個負責接收請求和回發請求,另一個負責中轉的去請求和接收。

重點一句話就是:每個請求産生一個線程處理,處理時關鍵是的延時處理(不然資料接收不全)。

現在上代碼,Proxy自定義類:

Proxy

using System;

using System.Collections.Generic;

using System.Text;

using System.Net;

using System.Net.Sockets;

using System.IO;

//by 路過秋天

namespace TCPProxy

{

    public class Proxy

    {

        Socket clientSocket;//接收和傳回

        Byte[] read = null;//存儲來自用戶端請求資料包

        Byte[] recvBytes = null;//存儲中轉請求傳回的資料

        public Proxy(Socket socket)

        {

            clientSocket = socket;

            recvBytes = new Byte[1024 * 1024];

            clientSocket.ReceiveBufferSize = recvBytes.Length;

            clientSocket.SendBufferSize = recvBytes.Length;

            clientSocket.SendTimeout = 10000;

            clientSocket.ReceiveTimeout = 10000;

        }

        public void Run()

        {

            #region 擷取用戶端請求資料

            string clientmessage = "";

            read = new byte[clientSocket.Available];

            int bytes = ReadMessage(read, ref clientSocket, ref clientmessage);

            if (bytes == 0)

            {

                Write("讀取不到資料!");

                clientSocket.Shutdown(SocketShutdown.Both);

                clientSocket.Close();

                return;

            }

            int port = 80;

            string url = GetUrl(clientmessage, port);

            #endregion

            try

            {

                #region IP解析擷取

                IPHostEntry IPHost= Dns.GetHostEntry(url);

                Write("-----------------------------請求開始---------------------------");

                Write("http://" + IPHost.HostName);

                string[] aliases = IPHost.Aliases;

                IPAddress[] address = IPHost.AddressList;//解析出要通路的伺服器位址

                Write("IP位址:" + address[0]);

                #endregion

                #region 建立中轉Socket及建立連接配接

                IPEndPoint ipEndpoint = new IPEndPoint(address[0], port);

                Socket IPsocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

                //建立連接配接Web伺服器端的Socket對象

                IPsocket.Connect(ipEndpoint);

                //Socket連Web接伺服器

                if (IPsocket.Connected)

                {

                    Write("Socket 正确連接配接!");

                }

                #endregion

                #region 發送中轉請求

                IPsocket.Send(read, 0);

                Write("發送位元組:" + read.Length);

                #endregion

                #region 接收中轉請求資料

                int length = 0, count = 0;

                do

                {

                    length = IPsocket.Receive(recvBytes, count, IPsocket.Available, 0);

                    count = count + length;

                    Write("正在接收資料..." + length);

                    System.Threading.Thread.Sleep(100);//關鍵點,請求太快資料接收不全

                }

                while (IPsocket.Available > 0);

                #endregion

                #region 關閉中轉請求Socket

                IPsocket.Shutdown(SocketShutdown.Both);

                IPsocket.Close();

                #endregion

                #region 将中轉請求收到的資料發回用戶端

                clientSocket.Send(recvBytes, 0, count, 0);

                Write("正在傳回資料..." + count);

                #endregion

                #region 結束請求,關閉用戶端Socket

                clientSocket.Shutdown(SocketShutdown.Both);

                clientSocket.Close();

                recvBytes = null;

                Write("完成,已關閉連接配接...");

                Write("-----------------------------請求結束---------------------------");

                #endregion

            }

            catch (Exception err)

            {

                System.Console.WriteLine(err.Message + err.Source);

            }

        }

        //從請求頭裡解析出url和端口号

        private string GetUrl(string clientmessage, int port)

        {

            int index1 = clientmessage.IndexOf(\' \');

            int index2 = clientmessage.IndexOf(\' \', index1 + 1);

            if ((index1 == -1) || (index2 == -1))

            {

                throw new IOException();

            }

            string part1 = clientmessage.Substring(index1 + 1, index2 - index1).Trim();

            string url = string.Empty;

            if (!part1.Contains("http://"))

            {

                part1 = "http://" + part1;

            }

            Uri uri = new Uri(part1);

            url = uri.Host;

            port = uri.Port;

            return url;

        }

        //接收用戶端的HTTP請求資料

        private int ReadMessage(byte[] readByte, ref Socket s, ref string clientmessage)

        {

            int bytes = s.Receive(readByte, readByte.Length, 0);

            clientmessage = Encoding.ASCII.GetString(readByte);

            return bytes;

        }

        private void Write(string msg)

        {

            // return;

            System.Console.WriteLine(msg);

        }

    }

}

在控制台裡調用:

代碼

using System;

using System.Collections.Generic;

using System.Text;

using System.Diagnostics;

using System.Net.Sockets;

using System.Threading;

namespace TCPProxy

{

    class Program

    {

        static void Main(string[] args)

        {

                Listen(8989);

        }

        static void Write(string msg)

        {

            Console.WriteLine(msg);

        }

        static void Listen(int port)

        {

            Write("準備監聽端口:" + port);

            TcpListener tcplistener = new TcpListener(port);

            try

            {

                tcplistener.Start();

            }

            catch

            {

                Write("該端口已被占用,請更換端口号!!!");

                ReListen(tcplistener);

            }

            Write("确認:y/n (yes or no):");

            string isOK = Console.ReadLine();

            if (isOK == "y")

            {

                Write("成功監聽端口:" + port);

                //偵聽端口号 

                Socket socket;

                while (true)

                {

                    socket = tcplistener.AcceptSocket();

                    //并擷取傳送和接收資料的Scoket執行個體 

                    Proxy proxy = new Proxy(socket);

                    //Proxy類執行個體化 

                    Thread thread = new Thread(new ThreadStart(proxy.Run));

                    //建立線程 

                    thread.Start();

                    System.Threading.Thread.Sleep(10);

                    //啟動線程 

                }

            }

            else

            {

                ReListen(tcplistener);

            }

        }

        static void ReListen(TcpListener listener)

        {

            if (listener != null)

            {

                listener.Stop();

                listener = null;

            }

            Write("請輸入監聽端口号:");

            string newPort = Console.ReadLine();

            int port;

            if (int.TryParse(newPort, out port))

            {

                Listen(port);

            }

            else

            {

                ReListen(listener);

            }

        }

    }

}

本人測試:

在打開IE-》工具->Internet選項->連結->區域網路設定->代理連接配接-》輸入IP和端口号

通路網站,檢視控制台輸出消息,頁面通路正常,測試通過。

本來想測試下QQ代理,無奈本地已被封,伺服器也沒端口可用。有空回家再測了。

提供代碼下載下傳

簡單實作Http代理工具