本來意圖是想寫個工具放到伺服器裡代理一下上秋秋的。
沒想到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代理,無奈本地已被封,伺服器也沒端口可用。有空回家再測了。
提供代碼下載下傳
![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLiETPwJWZ3ZCMwcTP39zZwpmLuJkbhV3ZU9UMFR1TxEFVPJTRUxkeFR0TwkkaOdXWU1ENBRUT4VkaNdXSUxUMrpmTx0keMdXRU1UeBpWT2VFVPJTV61kdjJjYzpkMMRXOykVdNNjW2hXbZVnTtx0dJRUT5N2ViBXO5xkNNh0YwIFSh9CXt92YuM3YltWas5iclN3Ztl2Lc9CX6MHc0RHaiojIsJye.jpg)