本篇是遊戲開發系列第一篇,如若你有興趣,請持續關注,後期會持續更新。其餘文章列表以下:算法
遊戲開發—協議設計json
通俗地說,協議就是通訊雙方可以理解的一種數據格式。維基百科這麼定義網絡協議:安全
網絡協議爲計算機網絡中進行數據交換而創建的規則、標準或約定的集合。bash
協議設計包含三要素:服務器
語法:語法是用戶數據與控制信息的結構與格式,以及數據出現的順序。網絡
語義:解釋控制信息每一個部分的意義。它規定了須要發出何種控制信息,以及完成的動做與作出什麼樣的響應。數據結構
時序:時序是對事件發生順序的詳細說明併發
也就是說,語義表示要作什麼,語法表示要怎麼作,時序表示作的順序。咱們要基於此來設計個人協議。
一般遊戲有一些特殊性,好比流量要儘可能的少,安全性要求更高,以及對平臺支持足夠多等等。這一切的需求就要求遊戲協議設計,儘可能簡單、通用,以及代碼層上易擴展、解析效率足夠高等特色。
基於此,我須要從如下幾個層次來考慮遊戲協議的設計方案。
由於知識點比較多,建議先讀知識圖譜,對總體結構有一個清晰的綜括。
應用層主要是經常使用是解析方式定義和解析,主要的選型,主要是看你基於什麼需求了,適用於實際需求就好。咱們經常使用的協議類型,主要有這兩種:文本協議、二進制協議
文本協議設計的目的就是方便人們理解,讀懂。如常見的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服務器之間的應用層通訊協議,適用很是普遍。但你也看到,有時候基於一個很簡單應答,就要帶上不少其餘的頭信息,這對於對流量有要求的遊戲應用來講,仍是很浪費的。
優勢:
一、通用,適用普遍
二、方便理解,可讀性好
缺點:
一、基於行讀,解析效率通常
二、攜帶附帶信息過多,傳輸的效率低下
三、無狀態,服務器不知道客戶端的狀態,必須基於客戶端的請求來回應,實時性低
四、很難嵌入其餘數據,對二進制支持差
若是你的遊戲對實時性要求不高,並且對流量要求不也是過高,文本協議也是個不錯的方式。通常短鏈接遊戲多適用這個。
二進制協議就是一串字節流,是一個典型的Ip協議,通常一般包括消息頭(header)和變長的消息體(body),消息頭的長度固定,消息體長度不固定,包含主要的內容主體。通常消息頭會包含消息體的長度,這樣就能基於頭信息從數據流中解析出一個完整的二機制消息了。
通常的格式以下:
咱們看到head部分定義包含:
cmd:命令字
sign:驗證串
content-leg:消息體長度
HeaderCRC:頭驗證(不是必須)
其中命令字是雙方協議文檔中規定好的,好比0x01表示登錄,0x02表示註冊等等,這些就是一個命令號。
sign是一個驗證字符串,對消息體數據進行必定加密驗證,保證數據安全。
content-leg是本次消息體的長度。
body部分,好比咱們以下定義:
message:login{
string username;
int64 passwoard;
}
咱們看到,由於字段的數據類型有定義,順序也有定義(第一個是string,第二個是int64),整個二進制流讀取的的時候,基於順序讀取就能夠很快的取出了。
優勢:
一、沒有冗餘字段,傳輸高效,耗費流量小
二、解析速度快,基於基礎數據類型操做
缺點:
一、可讀性差,不利於調試
二、擴展性差,對複雜數據結構支持不夠
若是你的遊戲,對實時性要求比較高,流量有要求,用二進制比較好,通常大型多人網遊,使用二進制協議來設計。
以上咱們看到了兩種協議類型,但對於消息體的解析介紹不多,消息體的格式決定了的他的語義和時序,格式不一樣數據的序列化和反序列化也是不一樣。好比message:login,你能夠基於json來定義,也能夠基於xml來定義,定義不一樣解析方式也各不相同。
通常的消息體格式主要有如下幾種:json、protocolBuff、xml、自定義
json
json 是一種輕量級的數據交換格式,互聯網應用的很普遍了。經常使用的框架也不少,推薦fastJson,解析速度仍是不錯的。json的好處是,開源,格式統一,解析速度也還能夠。缺點就是會有一些冗餘字符,不夠簡潔。
protocolBuff
protocolBuff是是google提供的一個開源序列化框架,相似於XML,JSON這樣的數據表示語言。可是比這些佔用空間都小,沒有冗餘字段。並且好處是靈活,解析速度快,易於開發(基於配置自動生成代碼),可支持語言也比較多。一條消息數據,用protobuf序列化後的大小是json的10分之一,xml格式的20分之一,是二進制序列化的10分之一
xml
很少解釋了,你們都用有過,強烈不建議使用這種,除了無效字符過多(標籤),並且解析效率比上面兩種都是很低的。
自定義
本身定義就是本身定義解析方式,好比經過文檔定義好一個消息的結構,第一個字段是什麼類型,第二個字段什麼類型...等等,基於此本身寫工具解析。好處是對外協議不透明,解析效率和傳送效率都還不錯,缺點就是開發難度高,不容易維護。
各類格式優缺點以下:
遊戲通訊,安全也很重要,否則協議被破解,用戶刷資源,整個遊戲的平衡性就被破壞了,輕者影響其餘玩家體驗,重則遊戲直接被廢。
通常的安全處理就是對協議進行加密。通常有如下幾種:
採用對稱加密或者hash加密來對消息內容進行加密,兩端採用同一種加密算法,基於同一個密鑰對消息體進行加密換算,以此來查看數據是否一致。
密鑰能夠用戶登錄的時候獲取一次。還有一種是基於每一個用戶密鑰不一樣,以此防止密鑰泄露大範圍影響全服玩家。
動態加密,能夠提早設置一個私有密鑰庫,裏面包含必定數量的密鑰,每次客戶端請求的時候,基於協議號來設計一個算法獲取其中一個密鑰。每一個協議的密鑰都是在協議到達的時候時時獲取的,這樣即使某一個協議的密鑰被破解,對其餘協議依然無效。
採用非對稱加密,或者加鹽處理。非對稱加密速度太慢了,不建議。
考慮服務端的承載成本,以及手機遊戲上網絡環境差,原則上UDP是比TCP更適合的方式。可是因爲遊戲對於數據完整性、安全性要求比較高,採用TCP的又可靠與安全。
目前採用netty做爲推送服務器的也有支持上百萬鏈接的應用了,tcp這塊性能對於通常遊戲支持足夠了。長連接遊戲多采用分區分服來應對高併發壓力,短連接多采用分佈式來應對。
二進制協議中,字節序須要注意,跨語言、平臺通訊的時候會出現亂碼問題。目前的字節序主要有,Little endian和Big endian之分,也就是常說的大頭和小頭之分。
具體是大頭在前仍是小頭在前,這個和主機的cpu有關係PowerPC系列採用big endian方式存儲數據,而x86系列則採用little endian方式存儲數據。這個在手機主機上也會出現。
應對方案是:
客戶端和服務端強制採用一種字節序,通常採用網絡字節序(big endian)
協議中出現浮點類型要特別注意,浮點類型的傳送上面字節序處理OK了,還得注意浮點數的多平臺運算不一致問題。
好比遊戲中要對尋路、戰鬥等公式計算,牽扯到浮點數了,有可能先後端算出的不一致,以Arm爲例,Arm的浮點數就有軟模擬、硬件IEEE-754兼容、SIMD下IEEE-754不兼容三種狀況。
此時解決方案,
一、統一一種格式,好比先後端都採用軟模擬,或者強制採用硬件IEEE-754(軟模擬速度慢)
二、轉換爲定點數,也就是浮點轉換爲整數(速度快)
掃描關注個人公衆號