遊戲開發—協議設計

wier發表於2019-02-18

本篇是遊戲開發系列第一篇,如若你有興趣,請持續關注,後期會持續更新。其他文章列表如下:

遊戲開發—協議設計

遊戲開發—協議-protobuf

遊戲開發-協議-protobuf原理詳解

通俗地說,協議就是通訊雙方能夠理解的一種資料格式。維基百科這麼定義網路協議:

網路協議為計算機網路中進行資料交換而建立的規則、標準或約定的集合。

協議設計包含三要素:

語法:語法是使用者資料與控制資訊的結構與格式,以及資料出現的順序。

語義:解釋控制資訊每個部分的意義。它規定了需要發出何種控制資訊,以及完成的動作與做出什麼樣的響應。

時序:時序是對事件發生順序的詳細說明

也就是說,語義表示要做什麼,語法表示要怎麼做,時序表示做的順序。我們要基於此來設計我的協議。

通常遊戲有一些特殊性,比如流量要儘量的少,安全性要求更高,以及對平臺支援足夠多等等。這一切的需求就要求遊戲協議設計,儘量簡單、通用,以及程式碼層上易擴充套件、解析效率足夠高等特點。

基於此,我需要從以下幾個層次來考慮遊戲協議的設計方案。

一、知識圖譜

因為知識點比較多,建議先讀知識圖譜,對整體結構有一個清晰的綜括。

二、協議三個層次

應用層

應用層主要是常用是解析方式定義和解析,主要的選型,主要是看你基於什麼需求了,適用於實際需求就好。我們常用的協議型別,主要有這兩種:文字協議、二進位制協議

1、文字協議:

文字協議設計的目的就是方便人們理解,讀懂。如常見的http協議,一般的常見http協議如下:

GET/sample.Jsp HTTP/1.1
Accept:image/gif.image/jpeg,*/*
Accept-Language:zh-cn
Connection:Keep-Alive
Host:localhost
User-Agent:Mozila/4.0(compatible;MSIE5.01;Window NT5.0)
Accept-Encoding:gzip,deflate
username=test&password=1234複製程式碼

這種格式非常貼近我們的文字描述,方便閱讀,而且目前HTTP也是客戶端瀏覽器或其他程式與Web服務器之間的應用層通訊協議,適用非常廣泛。但你也看到,有時候基於一個很簡單應答,就要帶上很多其他的頭資訊,這對於對流量有要求的遊戲應用來說,還是很浪費的。

優點

1、通用,適用廣泛

2、方便理解,可讀性好

缺點:

1、基於行讀,解析效率一般

2、攜帶附帶資訊過多,傳輸的效率低下

3、無狀態,伺服器不知道客戶端的狀態,必須基於客戶端的請求來回應,實時性低

4、很難嵌入其他資料,對二進位制支援差

如果你的遊戲對實時性要求不高,而且對流量要求不也是太高,文字協議也是個不錯的方式。一般短連線遊戲多適用這個。

2、二進位制協議

二進位制協議就是一串位元組流,是一個典型的Ip協議,一般通常包括訊息頭(header)和變長的訊息體(body),訊息頭的長度固定,訊息體長度不固定,包含主要的內容主體。一般訊息頭會包含訊息體的長度,這樣就能基於頭資訊從資料流中解析出一個完整的二機制訊息了。

一般的格式如下:

我們看到head部分定義包含:

cmd:命令字

sign:驗證串

content-leg:訊息體長度

HeaderCRC:頭驗證(不是必須)

其中命令字是雙方協議文件中規定好的,比如0x01表示登陸,0x02表示註冊等等,這些就是一個命令號。

sign是一個驗證字串,對訊息體資料進行一定加密驗證,保證資料安全。

content-leg是本次訊息體的長度。

body部分,比如我們如下定義:

message:login{

string username;

int64 passwoard;

}

我們看到,因為欄位的資料型別有定義,順序也有定義(第一個是string,第二個是int64),整個二進位制流讀取的的時候,基於順序讀取就可以很快的取出了。

優點

1、沒有冗餘欄位,傳輸高效,耗費流量小

2、解析速度快,基於基礎資料型別操作

缺點:

1、可讀性差,不利於除錯

2、擴充套件性差,對複雜資料結構支援不夠

如果你的遊戲,對實時性要求比較高,流量有要求,用二進位制比較好,一般大型多人網遊,使用二進位制協議來設計。

3、資料格式

以上我們看到了兩種協議型別,但對於訊息體的解析介紹很少,訊息體的格式決定了的他的語義和時序,格式不同資料的序列化和反序列化也是不同。比如message:login,你可以基於json來定義,也可以基於xml來定義,定義不同解析方式也各不相同。

一般的訊息體格式主要有以下幾種:json、protocolBuff、xml、自定義

json

json 是一種輕量級的資料交換格式,網際網路應用的很廣泛了。常用的框架也很多,推薦fastJson,解析速度還是不錯的。json的好處是,開源,格式統一,解析速度也還可以。缺點就是會有一些冗餘字元,不夠簡潔。

protocolBuff

protocolBuff是是google提供的一個開源序列化框架,類似於XML,JSON這樣的資料表示語言。但是比這些佔用空間都小,沒有冗餘欄位。而且好處是靈活,解析速度快,易於開發(基於配置自動生成程式碼),可支援語言也比較多。一條訊息資料,用protobuf序列化後的大小是json的10分之一,xml格式的20分之一,是二進位制序列化的10分之一

xml

不多解釋了,大家都用有過,強烈不建議使用這種,除了無效字元過多(標籤),而且解析效率比上面兩種都是很低的。

自定義

自己定義就是自己定義解析方式,比如通過文件定義好一個訊息的結構,第一個欄位是什麼型別,第二個欄位什麼型別…等等,基於此自己寫工具解析。好處是對外協議不透明,解析效率和傳送效率都還不錯,缺點就是開發難度高,不容易維護。

各種格式優缺點如下:

二、安全層

遊戲通訊,安全也很重要,不然協議被破解,使用者刷資源,整個遊戲的平衡性就被破壞了,輕者影響其他玩家體驗,重則遊戲直接被廢。

一般的安全處理就是對協議進行加密。一般有以下幾種:

1、常規加密

採用對稱加密或者hash加密來對訊息內容進行加密,兩端採用同一種加密演算法,基於同一個金鑰對訊息體進行加密換算,以此來檢視資料是否一致。

金鑰可以使用者登陸的時候獲取一次。還有一種是基於每個使用者金鑰不同,以此防止金鑰洩露大範圍影響全服玩家。

2、動態加密

動態加密,可以提前設定一個私有金鑰庫,裡面包含一定數量的金鑰,每次客戶端請求的時候,基於協議號來設計一個演算法獲取其中一個金鑰。每個協議的金鑰都是在協議到達的時候時時獲取的,這樣即便某一個協議的金鑰被破解,對其他協議依然無效。

3、其他

採用非對稱加密,或者加鹽處理。非對稱加密速度太慢了,不建議。

三、傳送層

考慮服務端的承載成本,以及手機遊戲上網路環境差,原則上UDP是比TCP更適合的方式。但是由於遊戲對於資料完整性、安全性要求比較高,採用TCP的又可靠與安全。

目前採用netty作為推送伺服器的也有支援上百萬連線的應用了,tcp這塊效能對於一般遊戲支援足夠了。長連結遊戲多采用分割槽分服來應對高併發壓力,短連結多采用分散式來應對。

四、一些問題

1、位元組序

二進位制協議中,位元組序需要注意,跨語言、平臺通訊的時候會出現亂碼問題。目前的位元組序主要有,Little endian和Big endian之分,也就是常說的大頭和小頭之分。

具體是大頭在前還是小頭在前,這個和主機的cpu有關係PowerPC系列採用big endian方式儲存資料,而x86系列則採用little endian方式儲存資料。這個在手機主機上也會出現。

應對方案是:

客戶端和服務端強制採用一種位元組序,一般採用網路位元組序(big endian)

2、浮點數

協議中出現浮點型別要特別注意,浮點型別的傳送上面位元組序處理OK了,還得注意浮點數的多平臺運算不一致問題。

比如遊戲中要對尋路、戰鬥等公式計算,牽扯到浮點數了,有可能前後端算出的不一致,以Arm為例,Arm的浮點數就有軟模擬、硬體IEEE-754相容、SIMD下IEEE-754不相容三種情況。

此時解決方案,

1、統一一種格式,比如前後端都採用軟模擬,或者強制採用硬體IEEE-754(軟模擬速度慢)

2、轉換為定點數,也就是浮點轉換為整數(速度快)

掃描關注我的公眾號

相關文章