Peercast原始碼是我第一次看超過2萬行的代碼,在這期間收穫很大,也積累了一些經驗。Peercast原始碼是我第一次看超過2萬行的代碼,
在這期間收穫很大,也積累了一些經驗,在此與大家分享,希望為大家看原始碼提供一些協助和參考.
這裡主要介紹的是在Visual Stdio6.0環境下,看Peercast的win32版本代碼的一些經驗
1.拿到原始碼的第一個步驟是編譯並運行,而且你首先要對如何使用它掌握得一清二楚
這是必不可少的步驟。一個無法編譯並啟動並執行原始碼對你毫無任何協助,而當你編譯成功後,以後你修改代碼的所有問題都是你的錯。
要深刻理解代碼顯然要先理解代碼產生的功能,所以你必須去運行它,先會用才能進一步掌握它的內部運行機制
所以,拿到Peercast源碼後,我希望你先弄清楚如何編譯即編譯的步驟,這我在《原始碼編譯方法》已經給出
你所要做的就是先將其編譯一遍從而確認沒有錯誤
然後掌握Peercast的運行方法,如何通過黃頁收聽廣播電台、如何通過地址方式收聽廣播電台、如何廣播MP3、WMV、ASF等檔案,如何查看日誌
和統計資料,這些都是不可忽略的步驟
2.理解整個系統是個拼圖的過程
這正如拼圖一般,剛開始你只是在小範圍內試著拼,慢慢地你看出來整體的一些端倪,然後你不斷地通過局部來理解整體,再從整體來理解局
部,最後拼成了最終的一幅完整的圖
所以,面對龐大的代碼千萬不要灰心,只要你足夠堅持,總能拼出那個完整的圖案
剛開始我也是被Peercast代碼所嚇倒,繁雜的類和函數,實在不敢相信我什麼時候才能夠看完,而且根本不知從何看起
這裡有幾點建議:
1.當不知道從何看起時,從程式的起始點看起總是一個不錯的手段,所以在看WIN32代碼時,一般從WinMain看起
2.在看C++代碼時,一般要先從各個類的定義看起,先弄清楚各個類是用來完成什麼功能的,再去理清類與類之間的相互關係,當然剛開始你都
是在猜測,然後是驗證
3.C++中往往是先通過幾個類產生這個類的對象,然後由這些對象再建立出其他的對象。因此對於程式初始時建立的一些對象尤其是全域對象,
你必須特別注意,因為他們貫穿整個代碼的始終,而且很有可能是串起整個代碼的核心所在。沒錯,我想如果你注意到了這三個全域對象的話
,你就知道重點在哪了,它們是sys、chanMgr、servMgr,它們永遠是我強調的重點。
4.看原始碼是個反覆的過程,甚而是個不斷延伸的過程。例如要理解函數A()必須去查看B(),由於它調用了B(),而為了理解B()又必須去查看
C()的代碼,這就必須要求你要清楚地知道你要理解的是什麼,即使你看到了F(),在這個過程中你要始終知道你是為了理解函數A()的功能,千
要不要迷失在代碼的海洋裡,你要記得抓住重點。很多函數本身就是個黑匣子,例如WSys類,剛開始的時候你不必去理解它是如何?的,只
須將其看成庫來使用就可以了。
5.分清類庫和核心類。Peercast的類庫都是自己實現的,所以你必須仔細分清類庫和核心類,核心類你要仔細研究,而類庫只需關心它是如何
使用的即可。例如FileStream類,你只需知道FileStream::write()是用來實現向檔案中寫資料就可以了,至於其內部如何?可以不去管它。
而向Servent類,你自然必須對它的各個函數的內部操作理解透徹。
總之,記著看代碼的過程中要有一條主線,同時分清重點和次要點。
所以,看代碼的步驟是:
概覽全域->找出重點->理解重點->查看分支->理解全域
而這是一個迭代的過程,每個迴圈你都在向最終目標又靠近了一層
當你拼圖時,如果你能大致看看整個拼圖的樣子,是否能為你提供很大的協助呢?
沒錯,所以你需要大體地先瀏覽一下整個代碼,弄清楚各個檔案和各個類大體起什麼作用(這些可以查看我的相應文章),對你將來代碼的閱
讀會提供很大的協助。
猜測是個很不錯的手段,尤其是在代碼品質高命名清晰的情況下,你往往可以猜到這個類或函數是完成什麼功能的
比如說你看到Channel類,你會猜想這個類應該是來完成頻道的建立、刪除工作的吧,沒錯,就是如此。
那麼,多個頻道是如何管理的呢?這時你注意到了ChanMgr類,ChanMgr,應該是Channel Manager的縮寫吧,而且你甚至可以猜想到ChanMgr類
應該包含Channel的多個對象。
好了,剩下來你要做的事情就是去驗證你的猜想是否準確了。
3.文檔
文檔絕對是個事半功倍的東西,所以你必須不惜任何代價去找到與這份代碼相關的文檔
Peercast沒有文檔,但有個好地方你不能不去,那就是Peercast的官方論壇,作者giles也在裡面發言,我從他的發言裡面學到了不少Peercast
的設計思想
所以我建議大家一定去www.peercast.org/forum看一下,不管是提示還是編程版塊,你總能找出自己需要的東西。在網上大量的資訊面前
找到自己真正需要的文檔是一項必備技能,我們需要一針見血。
另外用Peercast論壇的搜尋功能尋找giles的文章和你想瞭解的問題的關鍵字,這不失為一個好方法。
4.從記錄檔著手是個看原始碼的好方法
通常開原始碼都會有比較詳細的記錄檔記錄。通過查看記錄檔,可以很清晰地理清原始碼執行的流程,從而為理解原始碼提供方便。
例如我想理解Peercast啟動的代碼流程:
其中記錄檔如下:
SessionID: 002B372DA1F08103C65AA48DE4F28633
cmd: tip, arg: 202.205.16.102:7144"
allocated servent 1
allocated servent 2
Starting servers
Server started: 127.0.0.1:7144
Server started: 127.0.0.1:7145
Add hit: 202.205.16.102:7144/0.0.0.0:0
Searching for: 634F445C6F4160F85F7829954FFA5713 ()
New channel created
這樣我在原始碼中依次搜尋SessionID:、cmd:、allocate servent、Starting servers欄位
相應的執行函數豈不一目瞭然
bool ServMgr::start()
{
char idStr[64];
sessionID.toStr(idStr);
LOG_DEBUG("SessionID: %s",idStr);
}
void ServMgr::procConnectArgs(char *str,ChanInfo &info)
{
char arg[512];
char curr[256];
//使args等於?後面的字串,即tip=211.132.83.9:7144
char *args = strstr(str,"?");
if (args)
*args++=0;
info.initNameID(str);
if (args)
{
//nextCGIarg分解字串,把"tip"儲存到curr中,"211.132.83.9"儲存到arg中
while (args=nextCGIarg(args,curr,arg))
{
LOG_DEBUG("cmd: %s, arg: %s",curr,arg);
而且我也可以很清楚的看到LOG_DEBUG是用來輸出記錄檔用的,而ServMgr是個重要的類,可以用來提供初始化和串連等重要功能
這樣我要研究Peercast代碼,是不是可以從ServMgr著手呢,沒錯!
5.學會跨檔案搜尋是個很重要的手段
可以說跨檔案搜尋是閱讀原始碼的核心所在,我們想要查詢某個函數或者理解函數之間的調用關係,跨檔案搜尋是必要的手段
如果是VC6.0環境則比較簡單,只要選擇Find in files菜單,然後選擇好In folder即要查詢的檔案夾的路徑即可
LINUX比較麻煩一點,要學會用grep命令進行搜尋,但這是必經之路
6.拿到原始碼的第一個步驟是編譯並運行,而且你首先要對如何使用它掌握得一清二楚
這是必不可少的步驟。一個無法編譯並啟動並執行原始碼對你毫無任何協助,而當你編譯成功後,以後你修改代碼的所有問題都是你的錯。
要深刻理解代碼顯然要先理解代碼產生的功能,所以你必須去運行它,先會用才能進一步掌握它的內部運行機制
7.嘗試去修改和抄寫代碼
你是否理解代碼有個很簡單的衡量尺度,那就是,如果你能很輕易地修改它並且好無錯誤,你必然很深刻地理解了這段代碼,否則只是紙上談
兵而已,這正如看書,如果你無法對別人複述書的內容,那我也不相信你很好地理解了這本書的精髓
將你暫時難以理解的部分代碼原樣在電腦中敲打一遍也不失為一種好方式,這正如古人抄書一般。
8.將難以理解的代碼列印出來,找一個安靜的地方仔細研究
我們在電腦前總是容易喪失縝密思考的能力,所以你需要的是一個安靜的地方好好思考
哈哈,圖書館絕對是個好地方,是個去了就想學習和思考的好地方