總想寫一些東西,但總是發現想寫的內容還沒積累到可以寫出來的程度。沒有壓力是不行的,至少每月得來那么一次才對,不然就鬧出人命了。^3^
很羨慕那些做題的同學,每道題的算法都可以發一篇博文,可惜我多數情況下都看不懂也就不細看。不過有空的時候細看一篇,google其中理論,還是很長見識的。很久前我就看過一篇最大流最小割的,大學學過忘了,這次算記住了。
1.虛函數vs回調函數
可能通過繼承進行復用真不是什么好東西。
最初為bo2服務器組設計通信層的時候,使用的socket c++wrap lib的設計理念是通過繼承來對模式化的網絡編程代碼進行復用,以及通過實現指定的虛函數來開展應用上的業務。
1 class TcpSocket
2 {
3 virtual void OnRead();
4 virtual void OnConnect();
5 virtual void OnDisconnect();
6 };
這樣的接口,一看便知。最接近基本認識的做法,就是繼承TcpSocket,然后按業務需求實現那些虛函數。
第一版的bo2服務器組就是在這種想法下實現通信層的。這造成了一些問題,服務器組里面有很多服務器,每個服務器需要的TcpSocket子類并不是完全一致的,畢竟不同的連接處理的消息都不太一樣,于是TcpSocket的子類的數量就寫的有些多了,而且每個服務器都寫。
不久后,以將通信層劃入一個獨立的線程為契機,重構開始了。因為對第一版的設計不甚滿意加上多線程的情況下無法直接給應用層拿著TcpSocket的指針(這個庫默認情況自動析構已斷開的Socket對象),最終的手段是,實現唯一的TcpSocket子類,在虛函數中統一的調用3個與之對應但全局唯一的回調函數。于是,第二版展現的是,每個服務器都有一個類似network的模塊,實現這3個回調函數,不同的連接如果有不同的代碼的話,則根據連接的id進行跳轉。
總算砍斷繼承的鎖鏈了。
不過事情并沒有在這里就完全結束了。bo2服務器組并不會僅僅只有當前這些數量的服務器,以后隨著新的需求而將不斷增加,如何能讓新來的同學更快的開發新的業務服務器而不必在通信層上花費任何精力呢,答案就是把每個服務器的network模塊統一并入appbase中。
只是連接上某個服務器并不能成為bo2服務器組的一分子。連接誰,連接上之后要交代什么信息,這都是有規定的。而這些工作都是在每個服務器的network模塊單獨做的,勢必不能讓新同學為這些差不多重復的代碼而煩惱。
多數類似的服務器的network模塊并入appbase并不算太難,不過困難的是一些核心服務器,他們不太一樣,很多連接需要好幾個不同的onconnect和ondisconnect回調,可是第二版使用的是全局唯一的回調,而且現在也帶著默認代碼隱藏到appbase里了。
修改了一下,最終我讓每個連接都可以指定自己獨有的onconnect和ondisconnect回調,但是新同學不必擔心這個,因為他們什么也不需要指定和實現,他們只要在service模塊中專心處理消息就可以了。
繞了三版,得出的是每個連接都可以指定不同回調函數的方案(onRead是統一的),就跟TcpSocket的三個虛函數一樣,想想都好笑。不過有了繼承不是復用的好方式這種想法,算是一種收獲吧。
2.統一的定義stl庫包含頭
幾天前出了個bug,就是debug運行正常,release運行崩潰那種,崩潰的位置在一處list<t>::begin()調用上。最終查證的結果是因為bo2項目通過一些stl宏對stl容器進行了裁減,統一用std_inc.h導入stl庫,而崩潰的地方是很早的代碼,直接包含的是stl庫文件,引起不同編譯單元中對這個容器大小認識不一致,運行時崩潰。
結論是,如果在項目中使用stl庫,那么將所有常用的stl頭文件都寫在一個std_inc.h中,在使用stl的模塊中包含該文件,而不是其他,并建立預編譯頭導入該文件,就能避免出現類似的問題。
出bug的時候,完全不知如何下手,只好完全依賴更NB的同學,看著人家把崩潰的代碼拷到剛創建對象的地方,調試未崩,然后再在創建對象的地方調用崩潰代碼所屬的函數,調試崩潰。翻到我寫的類的頭文件中include的幾行說,stl容器大小不一致。
看得我是一臉慚愧。
3.
我蠻喜歡看包子山同學的GWeekly系列,不過他最近都不更新了。每周都寫博我是抗不住的,每月勒令自己的話,還是能嘮叨些文字的。仿照GWeekly的命名,我也來一個month-flow系列吧,實在沒有成體形的內容可寫的情況下,每月必定嘮叨一篇。
posted on 2009-06-07 21:46
LOGOS 閱讀(1723)
評論(1) 編輯 收藏 引用 所屬分類:
month-flow