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登陸時讓玩家選擇的六個伺服器入口實際上就是登陸伺服器。登陸伺服器主要完成Server Load Balancer的作用。詳細點說就是,在登陸伺服器的背後,有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討論