| 層級 | 類型 | 特點 |
| 應用層 | HTTP/FTP/SMTP Proxy | 理解協議內容,可過濾/修改/快取,需各協議支援 |
| 傳輸層 | Port Mapping / TCP Proxy | 透明轉發 TCP 流,通用但無法檢視應用層語義 |
| 會話層 | SOCKS4/5 | 標準化、支援認證、UDP 轉發、最靈活 |
本文實作 HTTP 應用層代理 (Web Proxy)。
HTTP 代理工作流程
- 客戶端瀏覽器設定代理 IP:Port,發送 HTTP 請求 (含完整 URL)
- 代理解析請求行取得目標 Host:Port
- 代理建立 Socket 連線目標 Web 伺服器 (預設 80 埠)
- 代理轉發原始請求給目標伺服器
- 代理接收回應 (含標頭 + 體)
- 代理轉發回應給客戶端
核心架構:每請求一線程
// 主線程:監聽 + 分派
TcpListener listener = new TcpListener(8000);
listener.Start();
while (true)
{
Socket clientSocket = listener.AcceptSocket();
var proxy = new ProxyHandler(clientSocket);
Thread t = new Thread(proxy.ProcessRequest);
t.Start(); // 或 ThreadPool.QueueUserWorkItem
}
ProxyHandler 核心實作
public class ProxyHandler
{
private readonly Socket _clientSocket;
private const int BufferSize = 4096;
public ProxyHandler(Socket clientSocket) => _clientSocket = clientSocket;
public void ProcessRequest()
{
try
{
// 1. 讀取客戶端請求
byte[] reqBuffer = new byte[BufferSize];
int bytesRead = _clientSocket.Receive(reqBuffer);
if (bytesRead == 0) return;
string request = Encoding.ASCII.GetString(reqBuffer, 0, bytesRead);
// 2. 解析目標 Host (簡易解析 GET https://host/path HTTP/1.1)
string host = ParseHost(request);
if (string.IsNullOrEmpty(host)) return;
// 3. 連線目標伺服器
IPAddress[] addresses = Dns.GetHostAddresses(host);
IPEndPoint remoteEP = new IPEndPoint(addresses[0], 80);
using (Socket serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
{
serverSocket.Connect(remoteEP);
if (!serverSocket.Connected) return;
// 4. 轉發請求
byte[] reqBytes = Encoding.ASCII.GetBytes(request);
serverSocket.Send(reqBytes);
// 5. 接收回應並轉發給客戶端 (串流式,避免大檔案記憶體壓力)
byte[] respBuffer = new byte[BufferSize];
int read;
while ((read = serverSocket.Receive(respBuffer)) > 0)
{
_clientSocket.Send(respBuffer, read, SocketFlags.None);
}
}
}
catch (Exception ex)
{
Console.WriteLine($"Proxy error: {ex.Message}");
}
finally
{
_clientSocket.Close();
}
}
private string ParseRequest(string request)
{
// GET https://www.example.com/path HTTP/1.1
// 取得 www.example.com
int start = request.IndexOf("https://");
if (start < 0) return null;
start += 7;
int end = request.IndexOf('/', start);
if (end < 0) end = request.IndexOf(' ', start);
if (end < 0) return null;
return request.Substring(start, end - start);
}
}
關鍵技術點
- 雙 Socket 模型:Client Socket (瀏覽器↔代理) + Server Socket (代理↔目標站)
- 串流式轉發:邊收邊送,避免大檔案佔用記憶體
- 編碼處理:HTTP 標頭為 ASCII/ISO-8859-1,Body 視 Content-Type 而定
- 連線復用:HTTP/1.1 Keep-Alive 需解析 Connection 標頭,維持雙向長連線 (進階)
- HTTPS 支援:CONNECT 方法建立隧道,需 TLS 握手透傳 (本範例未實作)
客戶端設定驗證
- IE/Edge/Chrome:設定 → 網路 → 代理 → 位址
代理IP、埠 8000
- 瀏覽任意 HTTP 網站,觀察代理主控台輸出
生產級強化建議
- 使用
SocketAsyncEventArgs / await SocketTaskExtensions 實現高併發非同步 I/O
- 引入快取 (MemoryCache/Redis)、過濾規則、存取日誌、流量統計
- 支援 HTTPS CONNECT 隧道、HTTP/2、WebSocket 升級
- 身份驗證 (Basic/Digest/NTLM)、IP 白名單、頻率限制
- 優雅關閉:停止接受新連線、等待進行中請求完成、釋放資源
- 考慮成熟專案:
Titanic、ProxyServer、Ocelot (API Gateway)
總結
本文展示了基於 TcpListener + Socket + 多線程的 HTTP 代理核心邏輯:解析請求 → 建立上游連線 → 雙向串流轉發。雖屬教學級實作,但涵蓋代理伺服器最本質的「橋樑」角色。現代高效能代理建議採用非同步 I/O (IOCP) + 管線化處理,並整合安全、可觀測性與協議擴展能力。
- 上一篇文章: C# 多線程程式設計入門:Thread 類核心功能與生命週期管理
- 下一篇文章: C# 列印機枚舉與驅動程式識別:從 WMI 到 Win32 API 的實戰遷移
Copyright ©
程式碼之家 All Rights Reserved