1. 程式人生 > >棋牌遊戲伺服器h5三公棋牌原始碼出售架構: 總體設計

棋牌遊戲伺服器h5三公棋牌原始碼出售架構: 總體設計

 首先要說明的是, 這個棋牌遊戲的伺服器架構h5三公棋牌原始碼出售 官網:h5.super-mans.com 企娥:2012035031 vx和tel:17061863513 h5三公棋牌原始碼出售參考了網狐棋牌的架構。網狐棋牌最令人印象深刻的是其穩定性和高網路負載。它的一份壓力測試報告上指出:一臺雙核r的INTEL Xeon 2.8CPU加上2G記憶體和使用共享100M光纖的機子能夠支援5000人同時線上遊戲。

      在研究其伺服器框架後發現,它的網路部分確實是比較優化的。它主要採用了Windows提供的IO完成埠來實現其網路元件。本伺服器雖然參考了其設計,但是還是有很大的不同,因為這個伺服器框架主要是用在linux系統之上,而網狐棋牌是基於Windows平臺的,嚴重依賴於windows sdk。這個架構延續了網狐棋牌在網路元件所作的努力,這個棋牌的伺服器也使用非同步IO作為網路的工作方式,更為徹底的是其資料庫也是採用非同步架構。boost::asio提供了一個非同步框架,所以它的幾個核心元件: TCPServerService, TimerService, DatabaseService, AsyncService中都可以看到boost::asio的影子。

,  圖1是總體架構圖。從圖上我們看到伺服器的整體架構分為三層:Libraries, Core和Applications。Core層基於Libraries實現,而Applications使用Core層提供的服務,並且要監聽Core層的非同步事件(Socket、Database等)。

   圖1  棋牌遊戲伺服器端總架構

Libraries 主要由4個庫組成,其中boost::thread是一個跨平臺的執行緒庫,boost::asio是跨平臺的非同步IO庫,protobuf則是用來序列化伺服器和客戶端協議的, libpq是開源資料庫postgresql提供的客戶端的官方介面,支援非同步資料庫操作。

Core 主要由4個Service組成,它們建立在Libraries的基礎之上。給應用層提供了網路,資料庫和定時器功能。AsyncService主要是Core內部自己使用。TimerService提供定時器功能,TCPServerServic管理著客戶端來的連線。而DatabaseService提供基本的資料庫訪問功能。

Applications是基於Core實現的4種伺服器,它們管理著遊戲資訊,提供登入以及處理遊戲邏輯的功能。下面是使用者與這些伺服器互動的一個經典流程:

      1) 客戶端將使用者名稱和密碼傳送給LogonServer登入,在登入驗證成功以後,將遊戲列表返回給客戶端。

      2) 玩家選擇具體遊戲進入房間時,客戶端傳送請求給RoomServer,RoomServer將房間的資訊返回給客戶端顯示

      3) 玩家選擇桌子坐下,遊戲開始。客戶端將遊戲動作傳送給相應的RoomServer, RoomServer將操作解析後轉發給遊戲邏輯模組進行處理,並將處理結果返回給客戶端。

這幾個伺服器這間的關係是:

      1) CenterServer維護遊戲列表資訊和房間資訊;

      2) LogonServer定時從CenterServer取回遊戲列表資訊和房間資訊;

      3) RoomServer在啟動時向CenterServer註冊,在關閉時從CenterServer登出, 以玩家進入房間時通知CenterServer更新線上人數。同時像LogonServer一樣定時連線CenterServer更新遊戲列表和房間資訊。

1 Libraries層

      boost::asio是一個非同步IO庫,提供了一個通用的非同步框架,並提供了基本的socket的非同步介面,它的主要功能是響應程式的非同步IO請求,在操作完成以後,將其加入到一個完成佇列之中, 在這個完成佇列上有一些工作執行緒在等著,這些工作執行緒從完成佇列上取出已經完成的操作,呼叫上層應用提供的一個完成函式--completaion handler。asio庫是通過學實現Proactor模式來完成這些工作的,在Windows是直接基於I/O completion port,而在類Unix系統中,是基於epool等函式使用Reactor模式來模擬的。 

      libpq是開源資料庫postgresql提供的客戶端介面庫。這裡選用postgresql是因為postgresql的跨平臺性以及其穩定性和高效能,另一方面是由於我對這個資料庫比較地熟悉。Libpq也對資料庫的連線、查詢、更新等提供了非同步實現。可以和boost::asio結合在一起提供統一地非同步操作介面。

      boost::thread庫是用C++實現的一個跨平臺的執行緒庫, 在C++11中,它已經被納入到了標準庫中。這個庫在這裡主要用來實現一個執行緒池,作為boost::asio的工作執行緒。主要是由Core層的AsyncService來維護。程式碼的其他地方不直接啟動執行緒。但是在非同步操作的完成函式中,對那些共享資料需要加鎖保護。

      protobuf庫是Google釋出的一個開源的用來序列化物件的高效能的庫,它支援多種語言,比如C++,Java,flash 等等。同時還將位元組序等瑣碎的東西封裝起來了,方便上層應用。

2 Core層

      核心層由4個Service: AsyncService、TCPServerService、TimerService、DatabaseService組成。下面是關於它們的基本描述. 

      AttemptService是Core內部使用的,它封裝了boost::asio和ThreadPool的功能,提供給其他幾個Service使用。從名字上可以看出,他的主要功能是給其他幾個Service提供非同步排程,這是通過boost::asio提供的功能來實現的,而ThreadPool是提供給boost::asio作為工作執行緒的。

      TCPServerService有一個連線池,管理著客戶端來的連線。內部通過AsyncService將socket讀寫完成訊息,通過應用層註冊進來的TCPServiceObserver通知到調到應用層去。它和Applications的互動包括:

      1)  Applications 呼叫 SetObserver註冊用來接收網路讀寫完成訊息;

      2)  Applications 呼叫 SendData 傳送資料;

      3)  Core在accept, recv完成後呼叫 Applications註冊的Observer。

      TimerService提供了定時器的功能,Applications層可以直接使用它來建立定時器,取消定時器。設定時間到來時,TimerService會呼叫建立定時器時指定的一個回撥函式。

      DatabaseService封裝了libpq,提供資料庫的基本操作。主要管理資料庫連線,執行查詢操作,執行儲存過程等。它的實現中有一個連線池。和socket操作一樣,它提供的資料庫操作都是非同步執行的,所以Applications層需要實現DBServiceObserver來監聽操作結果。

3 Applications

      前面的無論是libraries還是core,都是死的,只有applications加入了邏輯,它們是棋牌伺服器的主休。下面是關於它們的比較詳細的資訊

3.1 CenterServer

            圖2  CenterServer與外界的互動圖

      CenterServer不直接與玩家進行互動,它主要的功能是管理遊戲列表和房間資訊,包括:

      1. 遊戲型別資訊: 棋牌遊戲、休閒遊戲、視訊遊戲等。

      2. 遊戲種類: 比如在棋牌遊戲這個大類之下有:德州撲克、鬥地主、升級等。

      3. 站點資訊: 因為這個伺服器架構完全支援分散式,所以還儲存有站點的資訊

      4. 房間資訊: 維護當前有哪些房間以及房間當前的線上人數。

      CenterServer中有關遊戲列表的資訊是它在啟動的時候從ServerInfoDB這個資料庫載入的, 而它的房間資訊來自RoomServer,RoomServer在啟動時將自己註冊進來,在關閉的時候從CenterServer中登出自己。同時在玩家進入房間的時候,還會要求CenterServer更新線上人數。

  CenterServer還應該響應LogonServer和RoomServer的請求,將遊戲列表和房間資訊返回給它們。

3.2 LogonServer 

              圖3 LogonServer與外界互動圖

      LogonServer提供註冊新的遊戲玩家服務並且處理遊戲玩家的登入請求。

      LogonServer需要和UserInfoDB互動,這些互動包括:

      1. 在註冊的時候寫入註冊玩家的資訊。

      2.在玩家登入的時候與資料庫玩家資訊進行核對。

      LogonServer會定時地向CenterServer傳送更新遊戲列表和房間資訊的請求,因為這些資訊在不斷地變化,而LogonServer需要在玩家登入時將這些資訊返回給他們。

3.3 LogServer

  圖4  LogServer與外界的互動圖

      有時候,玩家可能會對遊戲的過程產生懷疑,或者想回顧整個遊戲的過程。這就需要伺服器將遊戲的過程以Log的形式儲存起來,供玩家檢查用。LogServer的就是用來響應玩家的核查的請求,然後從GameLogDB中將整個遊戲過程返回給客戶端,客戶端以視訊地方式顯示給玩家。 

      玩家在請求檢查的時候,客戶端會將這局遊戲的以及玩家的資訊id傳送到LogServer, LogServer根據遊戲id的資訊從GameLogDB取出日誌資訊返回給玩家。遊戲的過程可以用結構化語言描述出來,本來postgresql直接支援Json,也就是說Log可以以JSON的形式存在資料庫之中,但是由於可能會有位元組序的問題,所以Log的資訊也要用protobuf序列化了再存入資料庫。LogServer在從資料庫中讀出日誌後不用反序列化直接返回給客戶端反序列化。

3.4 RoomServer

      RoomServer可能是最重要的一類Server了,一個RoomServer會和一個遊戲模組結合在一起。它管理著遊戲的一個房間,處理玩家進入房間,找桌子座下的請求,並將遊戲相關的訊息轉發給遊戲模組進行處理。不僅不同的遊戲會有不同的RoomServer,即便是同一遊戲,也可能有多個RoomServer, 比如對於德州撲克來說,就可能有vip房間,普通房間等等,同一型別的房間也可能有Room1,Room2,這個可以根據玩家量按需架設。圖5給出了RoomServer與外界互動的圖。

圖5 RoomServer與外界的互動圖 

      RoomServer啟動的時候,先要傳送請求給CenterServer進行註冊,在關閉時要從CenterServer中登出。同時還會定時通知CenterServer更新線上人數, 定時從CenterServer上取回最新的遊戲列表和房間資訊。

      RoomServer需要和玩家進行互動。玩家進入房間,找桌子座下等的請求都由RoomServer來處理,而遊戲操作。比如說加註、發牌等 RoomServer會直接轉發給遊戲模組進行處理。

      RoomServer管理著一個線上使用者列表,在玩家進入房間,離開房間時這個列表隨之更新。這個列表中有關玩家的詳細資訊是從資料庫UserInfoDB中載入到的。 玩家在進行遊戲時,由於輸贏的關係,他的積分或者遊戲幣會隨著變化,為了記錄這些變化, 需要與GameDB進行互動。

      管理員可以通過RoomServer來發布訊息、踢出玩家、警告玩家、設定玩家許可權、設定房間屬性等活動。

      玩家也可以通過RoomServer參與聊天(包括大廳公聊和私聊)。

4 互動協議

      客戶端和伺服器進行互動時,傳遞的包需要使用protobuf來序列化。一個請求由一個container組成,container中可以包含一個或者多個請求包/應答包。每一個請求包和應答包都有如下基本結構:

圖6 伺服器和客戶端通訊的Package結構

nMainCmd 指示請求的類別,比如說遊戲請求,房間管理請求等

nSubCmd  指請求的具體是什麼,比如加註、踢出玩家等

nDataSize  指示pData欄位的長度

pData     可以是任何訊息,如果是一個結構,需要用protobuf序列化

5 資料庫

Database主要有3個: ServerInfoDB、UserInfoDB, GameDB。

ServerInfoDB: 主要儲存的是遊戲列表的資訊。這些資訊包括—遊戲種類列表、遊戲型別列表和站點資訊。

UserInfoDB: 主要儲存玩家相關的全域性資訊,包括玩家的 ID 號碼,帳戶名字,密碼,二級密碼,頭像,經驗數值,登陸次數,註冊地址,最後登陸地址等玩家屬性資訊。

GameDB:  主要儲存的是玩家的遊戲相關資訊,例如遊戲積分,勝局,和局,逃局,登陸時間等資訊