天天看點

知名網遊Server端架構分析

http://blog.csdn.net/sodme/archive/2004/12/12/213995.aspx

類似于QQ遊戲百萬人同時線上的伺服器架構實作 收藏 

本文作者:sodme 本文出處:http://blog.csdn.net/sodme

版權聲明:本文可以不經作者同意任意轉載,但轉載時煩請保留文章開始前兩行的版權、作者及出處資訊。

  QQ遊戲于前幾日終于突破了百萬人同時線上的關口,向着更為遠大的目标邁進,這讓其它衆多傳統的棋牌休閑遊戲平台黯然失色,相比之下,聯衆似乎已經根本不是QQ的對手,因為QQ除了這100萬的遊戲線上人數外,它還擁有3億多的注冊量(當然很多是重複注冊的)以及QQ聊天軟體900萬的同時線上率,我們已經可以預見未來由QQ建構起來的強大棋牌休閑遊戲帝國。

  那麼,在技術上,QQ遊戲到底是如何實作百萬人同時線上并保持遊戲高效率的呢?

  事實上,針對于任何單一的網絡伺服器程式,其可承受的同時連接配接數目是有理論峰值的,通過C++中對TSocket的定義類型:word,我們可以判定這個連接配接理論峰值是65535,也就是說,你的單個伺服器程式,最多可以承受6萬多的使用者同時連接配接。但是,在實際應用中,能達到一萬人的同時連接配接并能保證正常的資料交換已經是很不容易了,通常這個值都在2000到5000之間,據說QQ的單台伺服器同時連接配接數目也就是在這個值這間。

  如果要實作2000到5000使用者的單伺服器同時線上,是不難的。在windows下,比較成熟的技術是采用IOCP--完成端口。與完成端口相關的資料在網上和CSDN論壇裡有很多,感興趣的朋友可以自己搜尋一下。隻要運用得當,一個完成端口伺服器是完全可以達到2K到5K的同時線上量的。但,5K這樣的數值離百萬這樣的數值實在相差太大了,是以,百萬人的同時線上是單台伺服器肯定無法實作的。

  要實作百萬人同時線上,首先要實作一個比較完善的完成端口伺服器模型,這個模型要求至少可以承載2K到5K的同時線上率(當然,如果你MONEY多,你也可以隻開發出最多允許100人線上的伺服器)。在建構好了基本的完成端口伺服器之後,就是有關伺服器組的架構設計了。之是以說這是一個伺服器組,是因為它絕不僅僅隻是一台伺服器,也絕不僅僅是隻有一種類型的伺服器。

  簡單地說,實作百萬人同時線上的伺服器模型應該是:登陸伺服器+大廳伺服器+房間伺服器。當然,也可以是其它的模型,但其基本的思想是一樣的。下面,我将逐一介紹這三類伺服器的各自作用。

  登陸伺服器:一般情況下,我們會向玩家開放若幹個公開的登陸伺服器,就如QQ登陸時讓你選擇的從哪個QQ遊戲伺服器登陸一樣,QQ登陸時讓玩家選擇的六個伺服器入口實際上就是登陸伺服器。登陸伺服器主要完成負載平衡的作用。詳細點說就是,在登陸伺服器的背後,有N個大廳伺服器,登陸伺服器隻是用于為目前的用戶端連接配接選擇其下一步應該連接配接到哪個大廳伺服器,當登陸伺服器為目前的用戶端連接配接選擇了一個合适的大廳伺服器後,用戶端開始根據登陸伺服器提供的資訊連接配接到相應的大廳上去,同時用戶端斷開與登陸伺服器的連接配接,為其他玩家用戶端連接配接登陸伺服器騰出套接字資源。在設計登陸伺服器時,至少應該有以下功能:N個大廳伺服器的每一個大廳伺服器都要與所有的登陸伺服器保持連接配接,并實時地把本大廳伺服器目前的同時線上人數通知給各個登陸伺服器,這其中包括:使用者進入時的同時線上人數增加資訊以及使用者退出時的同時線上人數減少資訊。這裡的各個大廳伺服器同時線上人數資訊就是登陸伺服器為用戶端選擇某個大廳讓其登陸的依據。舉例來說,玩家A通過登陸伺服器1連接配接到登陸伺服器,登陸伺服器開始為目前玩家在衆多的大廳伺服器中根據哪一個大廳伺服器人數比較少來選擇一個大廳,同時把這個大廳的連接配接IP和端口發給用戶端,用戶端收到這個IP和端口資訊後,根據這個資訊連接配接到此大廳,同時,用戶端斷開與登陸伺服器之間的連接配接,這便是使用者登陸過程中,在登陸伺服器這一塊的處理流程。

  大廳伺服器:大廳伺服器,是普通玩家看不到的伺服器,它的連接配接IP和端口資訊是登陸伺服器通知給用戶端的。也就是說,在QQ遊戲的本地檔案中,具體的大廳伺服器連接配接IP和端口資訊是沒有儲存的。大廳伺服器的主要作用是向玩家發送遊戲房間清單資訊,這些資訊包括:每個遊戲房間的類型,名稱,線上人數,連接配接位址以及其它如遊戲幫助檔案URL的資訊。從界面上看的話,大廳伺服器就是我們輸入使用者名和密碼并校驗通過後進入的遊戲房間清單界面。大廳伺服器,主要有以下功能:一是向目前玩家廣播各個遊戲房間線上人數資訊;二是提供遊戲的版本以及下載下傳位址資訊;三是提供各個遊戲房間伺服器的連接配接IP和端口資訊;四是提供遊戲幫助的URL資訊;五是提供其它遊戲輔助功能。但在這衆多的功能中,有一點是最為核心的,即:為玩家提供進入具體的遊戲房間的通道,讓玩家順利進入其欲進入的遊戲房間。玩家根據各個遊戲房間線上人數,判定自己進入哪一個房間,然後輕按兩下伺服器清單中的某個遊戲房間後玩家開始進入遊戲房間伺服器。

  遊戲房間伺服器:遊戲房間伺服器,具體地說就是如“鬥地主1”,“鬥地主2”這樣的遊戲房間。遊戲房間伺服器才是具體的負責執行遊戲相關邏輯的伺服器。這樣的遊戲邏輯分為兩大類:一類是通用的遊戲房間邏輯,如:進入房間,離開房間,進入桌子,離開桌子以及在房間内說話等;第二類是遊戲桌子邏輯,這個就是各種不同類型遊戲的主要差別之處了,比如鬥地主中的叫地主或不叫地主的邏輯等,當然,遊戲桌子邏輯裡也包括有通用的各個遊戲裡都存在的遊戲邏輯,比如在桌子内說話等。總之,遊戲房間伺服器才是真正負責執行遊戲具體邏輯的伺服器。

  這裡提到的三類伺服器,我均采用的是完成端口模型,每個伺服器最多連接配接數目是5000人,但是,我在遊戲房間伺服器上作了邏輯層的限定,最多隻允許300人同時線上。其他兩個伺服器仍然允許最多5000人的同時線上。如果按照這樣的結構來設計,那麼要實作百萬人的同時線上就應該是這樣:首先是大廳,1000000/5000=200。也就是說,至少要200台大廳伺服器,但通常情況下,考慮到實際使用時伺服器的處理能力和負載情況,應該至少準備250台左右的大廳伺服器程式。另外,具體的各種類型的遊戲房間伺服器需要多少,就要根據目前玩各種類型遊戲的玩家數目分别計算了,比如鬥地主最多是十萬人同時線上,每台伺服器最多允許300人同時線上,那麼需要的鬥地主伺服器數目就應該不少于:100000/300=333,準備得充分一點,就要準備350台鬥地主伺服器。

  除正常的玩家連接配接外,還要考慮到:

  對于登陸伺服器,會有250台大廳伺服器連接配接到每個登陸伺服器上,這是始終都要保持的連接配接;

  而對于大廳伺服器而言,如果僅僅有鬥地主這一類的伺服器,就要有350多個連接配接與各個大廳伺服器始終保持着。是以從這一點看,我的結構在某些方面還存在着需要改進的地方,但核心思想是:盡快地提供使用者登陸的速度,盡可能友善地讓玩家進入遊戲中。

http://blog.csdn.net/sodme/archive/2005/06/18/397371.aspx

逆向思維--魔獸世界封包分析(1) 收藏 

本文作者:sodme

本文出處:http://blog.csdn.net/sodme

聲明:本文可以不經作者同意任意轉載,但任何對本文的引用都須注明作者、出處及此聲明資訊。謝謝!!

  特别聲明:

  本人非常欣賞暴雪及他們的遊戲,之是以寫這個文章,是想讓大家了解一些網絡封包分析方面的常見方法以及學習暴雪遊戲在網絡處理方面的經驗,偶認為作為一個網絡程式設計者,熟練掌握封包分析的工具和方法應該是其基本功之一。本文所列的所有封包分析内容,全部是采用普通黑箱方式即可得來的,并未涉及對魔獸世界可執行程式的逆向工程。同時,除此文涉及的内容外,本人拒絕向任何人透露更詳細的關于魔獸世界封包方面的更多内容,有興趣者請自己進行相關的試驗,本人在此文中也将盡量避免公開敏感的封包内容及相關加解密算法。謹以此文獻給忠愛的暴雪!

  一、登入子產品流程及封包分析

  我們先看登入流程。從封包流程來看,魔獸的登入流程是這樣的:

  1.由Client向登入/賬号伺服器(Login Server)發送使用者名及密碼等資訊。此資料包的最後部分是使用者名(明文表示,未加密),在使用者名的前一個位元組表示的是使用者名的長度。登入/賬号伺服器向Client傳回登入成功及後續連接配接到遊戲伺服器伺服器所必備的資訊等。這中間的兩個來往資料包,我還沒有看出具體有什麼作用。在這個互動過程中,由登入/賬号伺服器向Client發送所有的遊戲伺服器清單,伺服器清單資料包的内容包括:ip, port, 伺服器上所擁有的角色個數等資訊,因伺服器清單内容過多,被用戶端分為兩次接收完畢。

  2.Client收到Login Server的伺服器清單後,根據最近通路的伺服器辨別(這個資訊應該是包含在那個伺服器清單資料包中),連接配接到最近遊戲的那個遊戲伺服器(Game Server)。連接配接成功後,Game Server首先向Client發送一個8位元組的資料包,據以往的常識判斷,這個資料包的内容很可能是以後用戶端與伺服器通信的加密密鑰。

  3.Client向Game Server再次發送自己的賬号資訊。Game Server與Client經過兩個資料包的互動後,向Client發送角色資料包,此包中包括了玩家在該Game Server所建立的所有角色資訊,當然這個資訊隻是部分的,并不是該角色的所有資訊。

  4.在此後的通信過程中,Client每隔30秒向Game Server發送一個保持連接配接的包,該包長度為10位元組,包的最後四位元組是一個遞增數字,前面6位元組暫時未看出規律。

  5.隻要Client沒有點選某個角色進入最終的Game Server,則Client要始終與Login Server保持連接配接。當Client點選角色進入Game Server時,Client才與Login Server斷開連接配接。在以後的遊戲過程中,Client始終與且僅與該Game Server進行資料通信。

  通過對登入流程中的資料包初步分析,可以得出以下幾個結論:

  1.Client向Login Server發的第一個資料包,使用者名部分是采用明文的,且該資料包的内容,每次登入都一樣,并沒有因時間的不同而發生改變。由此可以推算:針對于此資料包中的密碼加密算法是固定不變的,換句話說,密碼的加密算法是比較容易通過逆向工程被找到的。偶認為,針對于此處,伺服器也應該先向用戶端發送一個加密密鑰,以後的通信可以用該密鑰作為安全驗證的依據。但暴雪沒有這樣作,最大的可能是為了提高伺服器的效率,在登入伺服器上,如果每個用戶端一旦連接配接成功,登入伺服器都得向用戶端廣播一個資料包的話,可能這個量還是比較大的,這可能延長了玩家的登入等待時間,是以他們沒有在這塊作。

  2.Client在登入Login Server的位址,每次Login Server的登入位址都可能是不一樣的。偶沒有在用戶端目錄裡找到這些位址,隻在用戶端目錄裡找到了四個大區的四個域名,我猜想,魔獸世界是用的DNS解析的簡單方法來實作Login Server的簡單動态均衡的。不知道這個猜想是否正确。

  3.“根據玩家最近在玩的哪個遊戲,由用戶端和伺服器自動為玩家選擇進入這個遊戲伺服器”,這一項設定充分展現了暴雪一貫的風格:為玩家着想,最大限度地提高遊戲的舒适度。再次對暴雪的态度予以肯定!

  4.一旦玩家進入了遊戲世界,用戶端與伺服器的通信端口會一直保持不變。即:魔獸世界的遊戲世界伺服器群設計結構采用的是帶網關的伺服器叢集。

  5.偶覺得在整個的登入流程中,讓我産生最大疑問的就是Login Server與Client的連接配接保持邏輯。當Client與Game Server連接配接了之後,Client并未與Login Server斷開,是一直保持連接配接的。後來,經進一步的抓包分析,Client之是以要與Login Server保持這樣的連接配接,是為了當Client重新選擇伺服器時,不至于重新連接配接Login Server。當Client點選了"選擇伺服器"按紐後,Login Server會每隔5秒向Client發一個目前所有的伺服器清單資料包。要知道,這個伺服器清單資料包的内容可是非常大的,如果有玩家就打開了這個視窗不關閉,Login Server向這種情況的所有玩家每5秒鐘就發一個伺服器清單資料包,這個廣播量可是很大的哦(2k左右,這可是一個使用者是2k哦)。偶認為這裡的邏輯設計是相當不合理的。Login Server如果為了給用戶端提供一個最新的全局伺服器清單,可以保持連接配接,但也沒必要每隔5秒就向用戶端發一個伺服器清單,最多隻在用戶端在某個伺服器上建立了不同的角色後再更新這個清單也是可以的,但隻用更新這個清單中的變化内容即可,不用發全部的完整包,這樣,在通信量上就小了很多。據說,魔獸剛開始的時候,産生DOWN機的原因就是登入子產品沒有處理好,偶不知道現在的這個情況是不是已經經過改良的了。但偶還是認為每隔5秒就向用戶端發送一個2K的包,這一點是不可以被接受的。

  以上隻是針對于魔獸世界登入流程的簡單分析,沒有多少技術含量,拿出來跟大家互相讨論讨論,看看有沒有可以借鑒的地方,後面還會有其它部分的封包分析。歡迎繼續關注偶的Blog: http://blog.csdn.net/sodme。

  偶在文章前面部分說過,作為一個網絡程式設計人員,熟練使用截包軟體和掌握基本的封包分析方法是其基本能力之一,發此文的目的一個原因也是希望向正在作網絡程式設計的兄弟介紹一下相關工具的使用和常見的分析方法。下面補充一下關于封包分析的基本方法和相關工具:

  1.你需要一個截包工具,偶推薦:commview,小巧但功能強大,支援自定義的封包分析插件以DLL形式裝載,也就是說隻要你願意,你可以寫個DLL對某類特殊形式的包進行顯示、記錄、解密等特别處理。

  2.如何檢視真正的封包資料。在commview裡,會詳細列出自網卡級别以上的各層封包資料,包括Ethernet層,IP層和TCP層。而我們作封包分析時,隻需要關注TCP層。但TCP層裡也有很多内容,對于我們的分析需求來說,我們需要關注的是其Data字段(在協定目錄裡可以看到"data length辨別,點選即可檢視data段")的内容。

  3.TCP的幾個狀态對于我們分析所起的作用。在TCP層,有個FLAGS字段,這個字段有以下幾個辨別:SYN, FIN, ACK, PSH, RST, URG.其中,對于我們日常的分析有用的就是前面的五個字段。它們的含義是:SYN表示建立連接配接,FIN表示關閉連接配接,ACK表示響應,PSH表示有DATA資料傳輸,RST表示連接配接重置。其中,ACK是可能與SYN,FIN等同時使用的,比如SYN和ACK可能同時為1,它表示的就是建立連接配接之後的響應,如果隻是單個的一個SYN,它表示的隻是建立連接配接。TCP的幾次握手就是通過這樣的ACK表現出來的。但SYN與FIN是不會同時為1的,因為前者表示的是建立連接配接,而後者表示的是斷開連接配接。RST一般是在FIN之後才會出現為1的情況,表示的是連接配接重置。一般地,當出現FIN包或RST包時,我們便認為用戶端與伺服器端斷開了連接配接;而當出現SYN和SYN+ACK包時,我們認為用戶端與伺服器建立了一個連接配接。PSH為1的情況,一般隻出現在DATA内容不為0的包中,也就是說PSH為1表示的是有真正的TCP資料包内容被傳遞。TCP的連接配接建立和連接配接關閉,都是通過請求-響應的模式完成的。

http://blog.csdn.net/sodme/archive/2005/07/10/419359.aspx

逆向思維----魔獸世界封包分析(2) 收藏 

本文作者:sodme

本文出處:http://blog.csdn.net/sodme

聲明:本文可以不經作者同意任意轉載、複制、傳播,但任何對本文的引用均須注明本文作者、出處及本行聲明資訊。謝謝!

  封包分析的手段,說簡單也挺簡單的,那就是:比較!要不斷地從不同的思維角度對封包進行對比分析,要充分發揮你的想象力不斷地截取自己需要的包進行比較。不僅要作橫向(同類)的比較,還要作縱向(不同類)的比較。即時對于同一個包,也要不斷地反複研究。

  初涉封包分析的新手,一般會不知道封包分析究竟該從何入手。基于經驗,本文将告訴你一般會從哪些類型的包入手進行分析以及應該怎樣對封包進行初步的分析。需要指出的是:封包分析是一件非常有趣但同時也非常考驗耐心的事,通常,半天的封包分析下來,會讓你眼前全是諸如“B0 EF 58 02 10 72....”之類的網絡資料,而且附帶有頭疼、頭暈症狀,是以,沒有充分的心理準備,還請不要輕易嘗試。呵呵。

  從事封包分析的基本前提是:應該了解和熟悉TCP協定,并知道資料包“粘合”是怎麼一回事。當然,我們平常截獲到的包,從數量上來看,隻有一小部分是屬于“粘合”的情況。但如果不了解它,将可能會對你的分析思路産生誤導和困惑。關于“粘包”的更詳細解釋,請參考我的另外一篇文章“拼包函數及網絡封包的異常處理(含代碼) (http://blog.csdn.net/sodme/archive/2005/07/10/419233.aspx)”。

  上一篇有關魔獸世界封包分析的文章(http://blog.csdn.net/sodme/archive/2005/06/18/397371.aspx)中,我根據用戶端與伺服器端連接配接及斷開事件的處理流程以及登入過程中的一些資料包分析了魔獸的架構和登入邏輯。這篇文章中,我将結合聊天資料包的分析,來闡述魔獸世界封包的大體結構。  

  首先解釋一下我們的目标:封包的大體結構。封包的大體結構包含哪些内容呢?一般情況下,封包的大體結構至少包括兩方面的資訊:

  1、一個封包是如何表示它的長度的?封包長度是由哪個字段表示的?(或者說:如何表示封包的開始和結束的)

  2、各種不同的封包類型是通過哪個字段表示的?

  是不是所有遊戲的封包都必然會有表示“長度”資訊的“字段”呢?答案是否定的。有的遊戲确實沒有采用這種方式,它們的作法設定特殊的包開始和包結束标志。但是,從應用的角度來看,偶推薦使用“長度”這樣的方法,因為不管在網絡底層的處理效率以及上層應用的處理便捷性來說,使用“長度”字段辨別一個完整的邏輯包都是比較好的辦法。在确定了封包的大體結構後,我們才友善分析具體類型包(比如聊天、行走等)的詳細結構。

  作資料包分析,在單純采用黑箱分析的階段,我們選取的資料包,須要是具有這種性質的,即:在資料包發送前用戶端未進行加密等處理時,這個資料包中的部分内容,我們是已經知道的。這樣的包,就可以作為封包分析的突破口。這樣看來,我們拿“聊天封包”作為第一個分析對象也就不難了解了,因為我們說的話,打上去的字,我們自己是知道的,但是我們說的話經過用戶端的處理後,發到網絡上的可能就是已經加了密的或者加了校驗碼的。站在黑箱分析的角度,我們能作的,就是不斷截取各種“聊天包”進行對比、判斷和總結。

  OK,打開你的commview。讓我們從“聊天封包”開始。

  分析“聊天包”的前提,是我們能夠正常判斷哪種類型的資料包是屬于聊天的,不要誤把行走或其它的資料包當作了聊天資料包。為了減小分析難度,建議新手到遊戲中人少或周圍沒有玩家的地方進行封包分析。這樣一來沒人打擾,二來你的網絡通信量會相對小得多,比較容易進行一些封包判定。

  第一步,我們需要确定用戶端與伺服器通信所用的端口,然後在commview的rules->ports中設定伺服器端口,截獲與該端口通信的所有資料包。伺服器端口的确定方法:不要使用其它網絡通信工具,打開commview,進遊戲,截包,觀察其通信端口。進行封包分析時,特别是初期的封包分析時,你的網絡通信應該盡可能是單一的,即:除了遊戲,其它的通信軟體盡可能不要開。但當你确定了伺服器的IP和端口後,就可以照常使用其它網絡軟體了。

  第二步,如前面述,在遊戲中找個人少或沒人的地方,開始“自言自語”,呵呵。說話的内容,建議以字母和數字為宜,不要說中文。因為中文是雙位元組的,而字母和數字是單位元組的,對于單位元組的資訊内容,截包軟體會以單位元組的文本資訊顯示,但對于雙位元組的漢字而言,截包軟體在對其進行顯示時由于換行等原因會造成部分中文顯示有亂碼,不容易直接看出中文内容。如果執意要說中文,偶也不攔你,給你推薦一個工具:String Demander(下載下傳位址:http://www.cnxhacker.com/Download/show/395.html),這個軟體,可以查詢中文所對應的編碼。

  第三步,設定好commview的rules并使之生效,開始截包。

  觀察通過以上的過程所截的包,可以發現,魔獸世界的聊天封包的說話内容是明文的!這一點,用不着大驚小怪,呵呵。聊天封包本身并不會對遊戲的關鍵邏輯造成損害,是以,即使讓其明文顯示也不足為奇。但是,我們還是不太相信自己的眼睛,于是再截若幹個包,發現包中的說話内容确實是明文的!但是,包的其它字段卻是我們一時看不懂的“密文”。

  看來,下面的事情就是對這些包裡的“密文”進行研究了。一般情況下,這種“密文”的加密方法,通過封包分析是分析不出來的,但,我們仍然可以通過封包分析來推論一些與“密文”生成算法有關的問題。我們可以作以下的對比分析:

  1、連續三次輸入“a”,并分别觀察及儲存封包資料;

  2、連續三次輸入“aa”,并分别觀察及儲存封包資料;

  3、連續三次輸入“aaa”,并分别觀察及儲存封包資料。

  輸入的封包用例,我們選擇了字母"a",它的ASCII碼是61。輸入的規律是:每種情況連續輸入三次,然後逐次增加a字母的個數。于是,我們發現這樣一個有趣的現象:

  1、包中有關說話的内容是明文的;

  2、即使針對于同樣的說話内容,比如“a”,用戶端所發出去的包也是不一樣的;

  3、當一次說話的字母個數增加1時,封包的總體長度也随之增加1;

  4、除每個封包的前面6個位元組以及說話的位元組外,其餘的封包内容每次都一樣;

  5、每個聊天封包的結尾位元組都是0。

  于是,我們可以試着得出如下結論:

  1、包是沒有壓縮的,它所使用的加密算法應該是按位元組進行的,并沒有改變封包的長度使之看上去使用統一的長度;

  2、包是以0結尾的(盡管我們不知道它是以什麼表示開頭的,呵呵);

  3、封包加密算法中所使用的密鑰是可變的,即針對于相同的資料包内容由于加密的密鑰不同,是以産生的密文也不同。由于用戶端的資料傳到伺服器端後,伺服器端還要對資料進行解密。是以,用戶端的加密算法與伺服器端的解密算法應該共用了前6位元組中的某些内容,以此作為解密算法的密鑰。如果這6位元組中沒有包含有關封包加、解密所需要的同步資料,那用戶端和伺服器之間應該會通過其它的方式同步這樣的資料。不過,偶傾向于前者,即:這6位元組中應該含有加、解密所需要的密鑰資訊。

  回頭看我們上面觀察到的有趣現象,針對于第2點,反過來想,這應該也是最起碼的功能了。就是說,即使用戶端作出的是同樣的動作,在用戶端發出的包中,包的内容也是不一樣的。這樣,外挂就不能靠單純的重複發相同的包而達到其目的了。

  分析來分析去,我們還是沒能确定魔獸封包的大體結構。其實,到現在,我覺得我此文的目的已經達到了,即向大家展示封包分析的思維角度和思維方式。至于具體結果,偶覺得倒真的不重要的了。可以肯定地告訴大家的是,魔獸的封包結構偶大緻已經掌握了。偶僅在此公布我的分析結果:

  1、魔獸的封包長度字段是每個封包的前兩位元組,它的表示方式是:前兩位元組的數值+2。之是以加這個2,是因為封包長度字段本身占用了兩個位元組的長度。

  2、魔獸的封包類型偶推斷是第三和第四位元組,其中普通聊天的類型辨別是“95 00”。

  請不要來信向我詢問任何有關魔獸封包破解的内容,偶能說的都已經在文章裡說了,偶之是以寫這個系列的文章不是想破解魔獸,而是想以這樣優秀的一款遊戲作為案例來向大家展示它在封包設計方面值得我們學習和讨論的地方,同時向更多的朋友普及有關封包分析的常識、工具以及思維方式,僅此而已。

  ps:由于每次封包分析的内容都很多,是以,一有了點結論後,要及時記錄和總結,并與之前取得的總結進行對比,及時更新相關的記錄文檔。

http://xiaogui9317170.javaeye.com/blog/276133

泡泡堂、QQ堂遊戲通信架構分析

作者:sodme

網站:http://blog.csdn.net/sodme/archive/2005/08/31/468327.aspx

之前,我分析過QQ遊戲(特指QQ休閑平台,并非QQ堂,下同)的通信架構(http://blog.csdn.net/sodme/archive/2005/06/12/393165.aspx ),分析過魔獸世界的通信架構(http://blog.csdn.net/sodme/archive/2005/06/18/397371.aspx ),似乎網絡遊戲的通信架構也就是這些了,其實不然,在網絡遊戲大家庭中,還有一種類型的遊戲我認為有必要把它的通信架構專門作個介紹,這便是如泡泡堂、QQ 堂類的休閑類競技遊戲。曾經很多次,被網友們要求能抽時間看看泡泡堂之類遊戲的通信架構,這次由于被逼交作業,是以今晚抽了一點的時間截了一下泡泡堂的包,正巧昨日與網友就泡泡堂類遊戲的通信架構有過一番讨論,于是,将這兩天的讨論、截包及思考總結于本文中,希望能對關心或者正在開發此類遊戲的朋友有所幫助,如果要讨論具體的技術細節,請到我的BLOG(http://blog.csdn.net/sodme )加我的MSN讨論..

  總體來說,泡泡堂類遊戲(此下簡稱泡泡堂)在大廳到房間這一層的通信架構,其結構與QQ遊戲相當,甚至要比QQ遊戲來得簡單。是以,在房間這一層的通信架構上,我不想過多讨論,不清楚的朋友請參看我對QQ遊戲通信架構的分析文章(http://blog.csdn.net/sodme/archive/2005/06/12/393165.aspx )。可以這麼說,如果采用與QQ遊戲相同的房間和大廳架構,是完全可以組建起一套可擴充的支援百萬人線上的遊戲系統的。也就是說,通過負載均衡+大廳+遊戲房間對遊戲邏輯的分攤,完全可以實作一個可擴充的百萬人線上泡泡堂。

  但是,泡泡堂與鬥地主的最大不同點在于:泡泡堂對于實時性要求特别高。那麼,泡泡堂是如何解決實時性與網絡延遲以及大使用者量之間沖突的呢?

  閱讀以下文字前,請确認你已經完全了解TCP與UDP之間的不同點。

  我們知道,TCP與UDP之間的最大不同點在于:TCP是可靠連接配接的,而UDP是無連接配接的。如果通信雙方使用TCP協定,那麼他們之前必須事先通過監聽+連接配接的方式将雙方的通信管道建立起來;而如果通信雙方使用的是UDP通信,則雙方不用事先建立連接配接,發送方隻管向目标位址上的目标端口發送UDP包即可,不用管對方到底收沒收到。如果要說形象點,可以用這樣一句話概括:TCP是打電話,UDP是發電報。TCP通信,為了保持這樣的可靠連接配接,在可靠性上下了很多功夫,是以導緻了它的通信效率要比UDP差很多,是以,一般地,在地實時性要求非常高的場合,會選擇使用UDP協定,比如常見的動作射擊類遊戲。

  通過載包,我們發現泡泡堂中同時采用了TCP和UDP兩種通信協定。并且,具有以下特點:

  1.當玩家未進入具體的遊戲地圖時,僅有TCP通信存在,而沒有UDP通信;

  2.進入遊戲地圖後,TCP的通信量遠遠小于UDP的通信量

  3.UDP的通信IP個數,與房間内的玩家成一一對應關系(這一點,應網友疑惑而加,此前已經證明)

  以上是幾個表面現象,下面我們來分析它的本質和内在。^&^

  泡泡堂的遊戲邏輯,簡單地可以歸納為以下幾個方面:

  1.玩家移動

  2.玩家埋地雷(如果你覺得這種叫法比較土,你也可以叫它:下泡泡,呵呵)

  3.地雷爆炸出道具或者地雷爆炸困住另一玩家

  4.玩家撿道具或者玩家消滅/解救一被困的玩家

  與MMORPG一樣,在上面的幾個邏輯中,廣播量最大的其實是玩家移動。為了保持玩家畫面同步,其他玩家的每一步移動消息都要即時地發給其它玩家。

  通常,網絡遊戲的邏輯控制,絕大多數是在伺服器端的。有時,為了保證畫面的流暢性,我們會有意識地減少伺服器端的邏輯判斷量和廣播量,當然,這個減少,是以“不危及遊戲的安全運作”為前提的。到底如何在效率、流暢性和安全性之間作取舍,很多時候是需要經驗積累的,效率提高的過程,就是邏輯不斷優化的過程。不過,有一個原則是可以說的,那就是:“關鍵邏輯”一定要放在伺服器上來判斷。那麼,什麼是“關鍵邏輯”呢?

  拿泡泡堂來說,下面的這個邏輯,我認為就是關鍵邏輯:玩家在某處埋下一顆地雷,地雷爆炸後到底能不能炸出道具以及炸出了哪些道具,這個資訊,需要伺服器來給。那麼,什麼又是“非關鍵邏輯”呢?

  “非關鍵邏輯”,在不同的遊戲中,會有不同的概念。在通常的MMORPG中,玩家移動邏輯的判斷,是算作關鍵邏輯的,否則,如果伺服器端不對用戶端發過來的移動包進行判斷那就很容易造成玩家的瞬移以及其它毀滅性的災難。而在泡泡堂中,玩家移動邏輯到底應不應該算作關鍵邏輯還是值得考慮的。泡泡堂中的玩家可以取勝的方法,通常是确實因為打得好而赢得勝利,不會因為瞬移而赢得勝利,因為如果外挂要作泡泡堂的瞬移,它需要考慮的因素和判斷的邏輯太多了,由于比賽程序的瞬息萬變,外挂的瞬移點判斷不一定就比真正的玩家來得準确,所在,在玩家移動這個邏輯上使用外挂,在泡泡堂這樣的遊戲中通常是得不償失的(當然,那種特别變态的高智能的外挂除外)。從目前我查到的消息來看,泡泡堂的外挂多數是一些按鍵精靈腳本,它的本質還不是完全的遊戲機器人,并不是通過純粹的協定接管實作的外挂功能。這也從反面驗證了我以上的想法。

  說到這裡,也許你已經明白了。是的!TCP通信負責“關鍵邏輯”,而UDP通信負責“非關鍵邏輯”,這裡的“非關鍵邏輯”中就包含了玩家移動。在泡泡堂中,TCP通信用于本地玩家與伺服器之間的通信,而UDP則用于本地玩家與同一地圖中的其他各玩家的通信。當本地玩家要移動時,它會同時向同一地圖内的所有玩家廣播自己的移動消息,其他玩家收到這個消息後會更新自己的遊戲畫面以實作畫面同步。而當本地玩家要在地圖上放置一個炸彈時,本地玩家需要将此消息同時通知同一地圖内的其他玩家以及伺服器,甚至這裡,可以不把放置炸彈的消息通知給伺服器,而僅僅通知其他玩家。當炸彈爆炸後,要拾取物品時才向伺服器送出拾取物品的消息。

  那麼,你可能會問,“地圖上某一點是否存在道具”這個消息,伺服器是什麼時候通知給用戶端的呢?這個問題,可以有兩種解決方案:

  1.用戶端如果在放置炸彈時,将放置炸彈的消息通知給伺服器,伺服器可以在收到這個消息後,告訴用戶端炸彈爆炸後會有哪些道具。但我覺得這種方案不好,因為這樣作會增加遊戲運作過程中的資料流量。

  2.而這第2種方案就是,用戶端進入地圖後,遊戲剛開始時,就由伺服器将本地圖内的各道具所在點的資訊傳給各用戶端,這樣,可以省去兩方面的開銷:a. 用戶端放炸彈時,可以不通知伺服器而隻通知其它玩家;b.伺服器也不用在遊戲運作過程中再向用戶端傳遞有關某點有道具的資訊。

  

  但是,不管采用哪種方案,伺服器上都應該保留一份本地圖内道具所在點的資訊。因為伺服器要用它來驗證一個關鍵邏輯:玩家拾取道具。當玩家要在某點拾取道具時,伺服器必須要判定此點是否有道具,否則,外挂可以通過頻繁地發拾取道具的包而不斷取得道具。

  至于泡泡堂其它遊戲邏輯的實作方法,我想,還是要依靠這個原則:首先判斷這個邏輯是關鍵邏輯嗎?如果不全是,那其中的哪部分是非關鍵邏輯呢?對于非關鍵邏輯,都可以交由用戶端之間(UDP)去自行完成。而對于關鍵邏輯,則必須要有伺服器(TCP)的校驗和認證。這便是我要說的。

  以上僅僅是在理論上探讨關于泡泡堂類遊戲在通信架構上的可能作法,這些想法是沒有事實依據的,所有結論皆來源于對封包的分析以及個人經驗,文章的内容和觀點可能跟真實的泡泡堂通信架構實作有相當大的差異,但我想,這并不是主要的,因為我的目的是向大家介紹這樣的TCP和UDP通信并存情況下,如何對遊戲邏輯的進行取舍和劃分。無論是“關鍵邏輯”的定性,還是“玩家移動”的具體實施,都需要開發者在具體的實踐中進行總結和優化。此文全當是一個引子罷,如有疑問,請加Msn讨論