棋牌遊戲服務器架構: 詳細設計(1) 內核設計

 內核的幾個組件被設計成Service,也就是說這幾個模塊都要實現以下接口:數據庫

      圖1  IService接口安全

Start方法用來啓動服務。架構

Stop 方法用來關閉服務。異步

IsService 方法用於查詢當前服務是否正在工做。函數

      內核中的幾個Service都不可以直接建立,Applications在使用這些Service的時候首先要獲得一個IServiceMgr的實例,這被實現成了一個另類地單例模式。IServiceMgr的接口定義以下:spa

               圖2  IServiceMgr接口線程

IServiceMgr提供兩類接口:設計

     1) 獲取Service的接口,這樣直接獲得具體的Service,是由於內核的Service比較固定。沒有必要用GetService(strServiceName)這種方法。server

GetAsyncService    返回AsyncService的實例對象

GetDBService        返回DatabaseService的實例

GetTCPService       返回TCPServerService的實例

GetTimerService    返回定時器實例

     2) 一個靜態的單例方法Instance。它申明在接口層,可是須要在IServiceMgr的實現中去實現它。它返回IServiceMgr的實例。

     因爲IServiceMgr的實現只是簡單地將IAttemptService,ITCPServerServer, IDatabaseService,ITimerService的實現組合在了一塊兒,因此它的實現不會詳細描述。

1 AsyncService詳細設計

                            圖3 AsyncService的詳細設計      

      AsyncService主要是提供給其餘3個Service使用的,它實現了IService接口和IAsyncService接口。由於與異步相關的功能基本上都被boost::asio實現,因此AsyncService主要只是管理boost::asio的實例 。

IAsyncService只提供了一個方法:

      GetIOService      返回一個可用的boost::asio::io_service的實例

      AsyncService組合了boost::asio和ThreadPool,其中boost::asio::io_service的數目和機器的cpu總數相同,而ThreadPool中線程總數爲2倍的cpu數。全部ThreadPool中的線程都將做爲工做線程,它們的入口函數都是io_service::run。

2 TimerService詳細設計

                                   圖4  TimerService的結構圖

TimerService實現了IService和ITimerService接口。ITimerService提供以下接口:

1) SetTimer(timerId,milisecs,timerFunc,repeatTimes)    設置一個id爲timerId的定時器,這個定時器會被激

發repeatTimes次,每兩次被小激發的時間間隔爲millsecs毫秒。每次被激發都會調用 timerFunc這個函數。

2) KillTimer(timerId) 取消id爲timerId的定時器。

3) KillAllTimer() 取消全部的定時器,通常用在系統關閉時調用。

      TimerService管理着一些TimerItem,Applications層用一個新的timerId,調用SetTimer時,TimerService就會建立一個新的TimerItem, 而在調用KillTimer時,就會銷燬掉與其相關的那個TimerItem。TimerService的實現依賴與AsyncService,由於定時器本質上也是異步操做。將由AsyncService中的io_service來統一調度。

須要注意如下幾點:

1) 傳給SetTimer的timerFunc這個函數要是線程安全的,由於不肯定會在哪一個工做線程的context中調用它,同時             若是你的好幾個定時器公用同一個timerFunc, 就可能對共享資源形成競爭。

2) SetTimer進若是發現已經存在相同id的TimerItem, 不會建立一個新的TimerItem,而是取消先前的定時器。修            改其參數後啓動。

3 TCPServerService詳細設計

                                 圖5  TCPServerService結構圖

      TCPServerService實現了IService接口和ITCPServerService接口。ITCPServerService的幾個主要接口說明:

      1) SendData 經過指定的ISocketItem發送數據, 數據在通常狀況下由4個參數: MainCmd, SubCmd, Data, DataSize (能夠參與總休設計中關於協議的部分的描述) 。有的時候Data爲空,就不須要Data和DataSize這兩個參數了。

      2) SendDataBatch 給全部鏈接發送數據。這是批量發送的,全部鏈接池中對應的客戶端都會收到。

      3) CloseSocket 關閉指定的鏈接。

      4) SetObserver 設置監聽者。用以接收異步通知。

      TCPServerService 管理着一個客戶端來的鏈接池。這個鏈接池由SocketItem組成,每個SocketItem都與一個整數標識對應,Applications使用這個標識來發送數據和接收數據。SocketItem主要提供下面幾個接口:

      1) GetIndex    獲取與其對應的惟一標識

      2) GetRound 因爲每一個SocketItem都是能夠重用的,因此爲了防止混亂,好比說一個SocketItem在前一時刻對應着client1, 可是如今對應着client2。client1曾經的一個請求如今纔要返回,這時若是沒有GetRound就會把client1的處理結果錯誤地返回給client2。從這裏也能夠看出,每一個SocketItem的round是在鏈接創建的時候會增長。

      3) IsConnected  是否處於鏈接狀態。

      4) SendData  發送數據。

      5) GetClientAddress 獲得客戶端的IP地址

      6) GetConnectTimer 獲取鏈接時間。

      7) Close  關閉鏈接。

      也許你會問了,我怎麼只看到發送數據的接口,而沒有接收數據的接口呢?由於這是個異步架構,在有鏈接到來,或者數據到來的時候,你會收到通知的。前提條件是你調用SetObserver設置了監聽者。TCPServerService的監聽都須要實現ITCPServiceObserver接口, TCPServerService經過這個接口提供的方法來通知你鏈接和讀取事件:

      1) OnSocketAccept  在新鏈接到達時,會調用你這裏面的內容。

      2) OnSocketRead 在數據讀取完成後,會調用你提供的這個方法作進一步處理。

      3) OnSocketClose 告訴你鏈接將要關閉。

      須要注意的是若是你這三個方法中有共享的數據,要加鎖保護。由於工做線程可能會產生競爭狀態。

      和TimerService同樣,TCPServerService的異步調度依賴於IAsyncService。

4.DatabaseService詳細設計

                                 圖6  DatabaseService結構圖

      能夠對比一下DatabaseService和TCPServerService的結構圖,你會發現他們是那麼地類似。對的,它們的設計思路一模一樣。DatabaseService實現了IService和IDatabaseService這兩個接口。

      IDatabaseService主要只提供了3個接口:

      1) Connect 鏈接到一個數據庫

      2) Query 進行查詢。 這裏有兩點要注意:1) Query之後不會立馬獲得結果,由於這是異步的; 2) 存儲過程的調用也得使用這個方法,你只要將query語句寫成 'select stroage_procedure(param1,param2,...)' 就好了。

      3) SetObserver 設置觀察者。由於查詢是異步的,因此你要設一個觀察者來獲得通知。

      DatabaseService管理着一些數據庫鏈接DBConnect, 每個DBConnect也與一個整數標識相關聯,能夠經過GetIndex得到。同時你能夠經過IsConnect來查詢這個DBConnect是否處於鏈接狀態。

      在實現IDBServiceObserver時,你須要實現下面兩個方法:

      1) OnDBConnect  在數據庫鏈接創建時會調用

      2) OnQueryEnd 在這裏你能夠獲得一個表示查詢結果的QueryResult對象。你能夠經過它知道查詢的狀態,以及結果信息。

相關文章
相關標籤/搜索