程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> 關於C++ >> Muduo 網絡編程示例(十)socks4a 代理服務器

Muduo 網絡編程示例(十)socks4a 代理服務器

編輯:關於C++

本文介紹用 muduo 實現一個簡單的 socks4a 代理服務器,代碼見 http://code.google.com/p/muduo/source/browse/trunk/examples/socks4a/ 。

TCP 中繼器

在實現 socks4a proxy 之前,我們先寫一個功能更簡單的網絡程序—— TCP 中繼器 (TCP relay),或者叫做窮人的 tcpdump (poor man's tcpdump)。

一般情況下,客戶端程序直接 連接服務端,如下圖。有時候,我們想在 client 和 server 之間放一個中繼器 (relay),把 client 與 server 之間的通信內容記錄下來。這時用 tcpdump 是最方便省事的,但是 tcpdump 需要 root 權 限,萬一沒有 root 密碼呢?窮人有窮人的辦法,自己寫一個 relay,讓 client 連接 relay,再讓 relay 連接 server,如下圖中的 T 型結構,relay 扮演了類似 proxy 的角色。

TcpRelay 是我們自己寫的,可以動動手腳。除了記錄通信內容,還可以制造延時,或者故意 翻轉 1 bit 數據以模擬 router 硬件故障。

TcpRelay 的功能(業務邏輯)看上去很簡單,無 非是把連接 C 上收到的數據發給連接 S,同時把連接 S 上收到的數據發給連接 C。但仔細考慮起來, 細節其實不那麼簡單:

建立連接。為了真實模擬 client,TcpRelay 在 accept 連接 C 之後才向 server 發起連接 S,那 麼在 S 建立起來之前,從 C 收到數據怎麼辦?要不要暫存起來?

並發連接的管理。上圖中只畫出了一個 client,實際上 TcpRelay 可以服務多個 clients,左右兩 邊這些並發連接如何管理,如何防止串話(cross talk)?

連接斷開。Client 和 Server 都可能主動斷開連接。當 Client 主動斷開連接 C 時,TcpRelay 應 該立刻斷開 S。當 Server 主動斷開連接 S 時,TcpRelay 應立刻斷開 C。這樣才能比較精確地模擬 Client 和 Server 的行為。在關閉連接的剎那,又有新的 client 連接進來,復用了剛剛 close 的 fd 號碼,會不會造成串話? 萬一 Client 和 Server 幾乎同時主動斷開連接,TcpRelay 如何應對?

速度不匹配。如果連接 C 的帶寬是 100KB/s,而連接 S 的帶寬是 10MB/s,不巧 Server 是個 chargen 服務,會全速發送數據,那麼會不會撐爆 TcpRelay 的 buffer?如何限速?特別是在使用 non-blocking IO 和 level-trigger polling 的時候如何限制讀取數據的速度?

在看 muduo 的實現之前,請讀者思考:如果用 Sockets API 來實現 TcpRelay,如何解決以上這些 問題。

TcpRelay 的實現很簡單,只有幾十行代碼 http://code.google.com/p/muduo/source/browse/trunk/examples/socks4a/tcprelay.cc,主要邏輯 都在 Tunnel class 裡

http://code.google.com/p/muduo/source/browse/trunk/examples/socks4a/tunnel.h 。這個 實現解決了前三個問題,第四個留給將來吧。

Socks4a 代理服務器

Socks4a 的功能與 TcpRelay 非常相似,也是把連接 C 上收到的數據發給連接 S,同時把連接 S 上收到的數據發給連接 C。它與 TcpRelay 的區別在於,TcpRelay 固定連到某個 server 地址,而 socks4a 允許 client 指 定要連哪個 server。在 accept 連接 C 之後,Socks4a server 會讀幾個字節,以了解 server 的地 址,再發起連接 S。

Socks4a 的協議非常簡單,請參考維基百科 http://en.wikipedia.org/wiki/SOCKS#SOCKS_4a 。

muduo 的 socks4a 代理服務器的實現在 http://code.google.com/p/muduo/source/browse/trunk/examples/socks4a/socks4a.cc,它也使用了 Tunnel class。與 TcpRelay 相比,只多了解析 server 地址這一步驟。

muduo 這個 socks4a 是個標准的網絡服務,可以供 Web 浏覽器使用(我正是這麼測試它的)。

n:1 與 1:n 連接轉 發

雲風在《寫了一個 proxy 用途你懂的》中寫了一個 TCP 隧道 tunnel,程序由三部分組成: n:1 連接轉發服務,1:n 連接轉發服務,socks 代理服務。

我仿照他的思路,用 muduo 實現了 這三個程序。不同的是,我沒有做數據混淆,所以不能用來翻傳說中的牆。

n:1 連接轉發服務就是《Muduo 網絡編程示例之七:“串並轉換”連接服務器及其自動化測試》中 的 multiplexer (數據選擇器)。

1:n 連接轉發服務是該文提到的 backend,一個數據分配器(demultiplexer),代碼在 http://code.google.com/p/muduo/source/browse/trunk/examples/multiplexer/demux.cc

socks 代理服務正是本文實現的 socks4a。

有興趣的讀者可以把這三個程序級聯起來試一試。

Muduo 編程示例系列告一段落

《Muduo 網絡編程示例》從今年2月初開始寫,到今天正好是四個月,我寫了十一篇博客,基本按計劃 完成了任務。這個系列暫告一段落。

這個系列基本涵蓋了 muduo 為編寫單線程服務端和客戶端 TCP 網絡程序提供的功能,muduo 的能力不止於此:

多線程,muduo::net::TcpServer 內置了一個簡單但適應性很強的線程模型。目前博客上的例子涉 及的業務邏輯很簡單,沒有復雜的運算,瓶頸通常在 IO 上,多線程的優勢發揮不出來。

高級應用。比方說用 muduo::net::Channel 配合 signalfd 來處理信號;其他非阻塞網絡客戶端庫 (例如 ZooKeeper 的 C 客戶端,PostgreSQL 的客戶端 libpq)與 muduo EventLoop 的集成。

以上兩點在以後的文章裡會提及,不會明珠暗藏。

Muduo 在 2010 年 8 月底發布 0.1.0 版 ,隨著這個編程示例系列文章的發表,迄今已發布了 14 次小升級,下載地址: http://code.google.com/p/muduo/downloads/list

接下來的計劃

接下來,我還會寫一 系列博客,目前想到的有:

談一談我的網絡編程學習經驗。文章已經完成大半,端午節之後可以發布。

muduo 設計與實現系列,介紹如何一步步實現一個非阻塞網絡庫。代碼已經准備得差不多了,在 https://github.com/chenshuo/recipes/tree/master/reactor

用 muduo 實現一些稍微復雜一些的網絡程序,比如小規模的分布式系統。計劃有:利用 Paxos 算 法實現一個高可用的 in-memory key value 存儲,在此基礎上實現 naming service,然後實現我以前 多次提到的簡單機群管理系統等等。目前 muduo 的示例程序都是簡單獨立的網絡程序,下半年我想多 寫一寫由多個程序組成的系統,具體談一談分布式系統細節設計。

查看本欄目

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved