網絡遊戲-斷線重連

轉載自:https://www.jianshu.com/p/110d1f0b457d

 

1、背景

移動網絡信號波動頻繁,給移動遊戲開發者帶來諸多困擾,處理不好會造成較差的用戶體驗以及重複扣道具等嚴重問題。因此弱網絡問題在TDR技術評審中作爲客戶端重點挑戰項,並且弱網絡專項測試達標後方能上線。本文就過往項目中遇到的問題給出一種比較通用解決方案。

2、網絡連接方式

通常遊戲客戶端都是通過創建socket與服務器取得連接,但也會根據使用場景劃分成兩種連接方式:TCP連接和HTTP連接。

1) TCP連接即我們常說的長連接。這種連接方式下socket連接一旦建立,通信雙方即可相互發送數據,直到一方終止連接。目前公司的移動端聯網遊戲多采用這種數據通訊方式。

2) HTTP連接即我們常說的短連接。這種連接採用的是“請求-響應”的通訊方式,每次交互由客戶端發起請求,服務器收到請求後才能回覆數據,數據傳輸完成後,socket連接便斷開。在下載CDN資源或雲配置時通常會採用這種連接方式。

3、網絡檢測

3.1 檢測設備的網絡環境

iOS和Android都提供了檢測本地網絡環境的方法,具備我們需要的功能:

1) 網絡環境標識,區分當前網絡環境:WIFI/WWLAN/NOTREACHABLE等。

2) 網絡切換感知,網絡環境切換後會收到系統消息。

在蘋果開發者網站(developer.apple.com)上有一個reachability的例子,對底層網絡組件做了封裝,可實現此上的功能。Android上提供了Connectivity Manager服務,可加以封裝實現同樣的功能。附錄中提供了相關的開源代碼,並分別封裝了reachability在iOS和Android平臺上的實現。

3.2 檢測心跳超時和回包超時

心跳即每一定時間間隔(假定15秒)客戶端和服務器進行一次請求/應答,來判斷對方是否存活。若客戶端發送請求成功後,長久(假定60秒)未收到服務器的迴應,則認爲連接已經中斷或者服務器宕機。若服務器長久(假定300秒)未收到客戶端請求,則可以認爲客戶端已經離線。另外常規的業務數據包也可以認爲是心跳包的擴展,所以每次業務數據包通信成功,客戶端和服務器都要重新計時。一般心跳包是一個空的數據包,以節約流量,但通常也會包含少量字段,比如客戶端和服務器的時間同步信息等。

一些關鍵協議,比如進入房間的請求,需要等待服務迴應後才能扣除體力進入房間。但網絡不穩定時,可能客戶端的請求發送成功,服務器的迴應卻遲遲沒有收到,這種情況下,客戶端需要做一個超時控制,比如15秒後客戶端還沒有收到回包,則給出提示,不能讓客戶端無限的等待。這種因果關聯的一對協議我們稱作請求-應答協議,建議所有關鍵協議都採用這種機制。有一點要注意,這種異步操作有一個等待的時間,一般這段時間都會屏蔽輸入(轉菊花/show activity indicator),避免用戶進行其他操作導致重複請求。這也要求我們在代碼邏輯層面上避免多個關鍵協議的嵌套和併發。

3.3 檢測發包失敗

一般來講reachability足夠靈敏可靠,設備網絡發生變化時能及時感知,只要監聽到狀態切換爲NOTREACHABLE便可認爲斷線了(需要排除瞬斷的情況),但reachability也有限制,無法感知到傳輸層連接斷開。舉個例子:手機和無線路由器連接正常,但是無線路由器和modem連接中斷,這時reachability是檢測不到網絡斷開的。此時需要依據socket錯誤碼來判斷網絡情況。

3.4 檢測socket狀態

以上幾種機制都是在應用層做網絡狀況檢測,基本上可以應對大部分情況,但有時爲了更好的用戶體驗,我們需要更加精準的檢測方式。獲取socket底層錯誤碼及狀態能爲我們提供更多的判斷依據。因實際項目中並未用到這方面的內容,便不在這裏擴展。

3.5 檢測網絡延遲

某些類型的遊戲對網絡延遲特別敏感(如實時對戰類遊戲),較高的網絡延遲將會導致慘不忍睹的體驗。這些類型的遊戲不但要從技術層面做優化,同時也要根據用戶當前的網絡延遲加以限制。比如平均延遲在1000ms以上便提示無法遊戲。我們可以採用兩種方式評估延遲:信號強度(received signal strength indication)和收發包時間統計。

1) 信號強度(RSSI)檢測:這種判斷網絡延遲的方式不具客觀性,因爲網絡延遲不僅取決於信號強度,同時受到帶寬、傳輸節點數、網絡硬件吞吐量等一系列因素的影響。但在其他參數相對固定的情況下,我們仍然可以參考信號強度來評判網絡狀況,同reachability類似,RSSI能及時給我們當前網絡狀態的反饋。在Android平臺上使用WifiManager類可以獲取具體RSSI值及信號強度等級。不幸的是iOS 5.0及以後的系統都不再支持RSSI的獲取(當然jailbreak之後還是可以的)。

2) 收發包時間統計:即在客戶端和服務器時間同步的情況下,每個數據包帶一個時間戳信息,基於過往的數據包計算平均網絡延遲。這種檢測方式相對合理,但是時效性較差,在網絡波動頻繁時不能及時正確評估,相反在連接平穩的網絡環境中,會得到理想的效果。

在Android平臺上要取得一個合理的網絡延遲,可以結合以上兩種方式。iOS平臺上暫時還只能採用第二種方式。

4、斷線重連機制

當檢測到斷線後,便可以啓動重連模式。根據當前的遊戲狀態確定重連策略,一般有以下三種方式:

1) 靜默重連,即在用戶無感知的情況下進行重連。一般檢測到斷線後,可以先嚐試靜默重連一定次數(比如3次)。如果在遊戲對戰過程中斷線,一般也會盡量嘗試靜默重連並且忽略重連次數,因爲此時彈出提示框會打斷對戰體驗的完整性。靜默重連提供了一種友好的用戶體驗,能應付一些短暫的網絡中斷(比如進出電梯或者進程從後臺喚醒等)。

2) 顯式重連,在靜默重連一定次數(假定3次)之後,仍然無法連接成功的情況下,此時需要彈出提示框,中斷遊戲流程,告知用戶當前網絡環境較差,引導用戶在網絡較好時再嘗試連接。

3) 服務器故障重連,這種情況下客戶端無論如何是連接不到遊戲服務器的。此時客戶端也需要給出正確的引導,而不是誤當作斷線故障處理。因此我們在斷線重連失敗之後多加一個步驟:嘗試連接CDN服務器,若CDN服務器可以正常連接,那麼說明網絡暢通,我們去獲取CDN上的雲配置,檢查是否有服務器日常維護的標識,如果有則給出服務器日常維護的公告,否則可以認爲服務器宕機,則給出服務器故障的公告。此步驟中若CDN服務器也無法連接,說明網絡確實不暢通,可以繼續走重連流程或者等待。

5、網絡協議的制定規範

要做到良好的重連體驗,不僅需要良好的解決方案,也需要有協議上的支持。通常協議制定時可以參考以下規則:

1) 登錄協議儘量簡單,僅包含必須的字段(如玩家等級,金錢,體力等)。一般重連即需要走重新登錄和鑑權流程,精簡的登錄協議能提高重連效率和節約流量。用戶的非關鍵校驗數據(比如揹包數據,排行榜,卡牌信息)等可以延遲到界面開啓時再請求或者使用本地緩存數據。

2) 協議的解耦,不同業務邏輯需要的請求包不同,這裏就需要進行協議解耦,減少冗餘數據,降低傳輸的包量,提高單包發送成功率。

3) 支持數據包壓縮,對於較大的協議包(比如排行榜數據,好友數據等)需要做針對性的壓縮,提高單包發送成功率。

4) 關鍵協議需要添加序列號,避免客戶端重複請求造成的多次扣費等問題。

6、CDN資源下載方案

隨着硬件和技術的發展,移動遊戲品質也和PC端遊越來越接近,當然資源量也越來越接近。受限於移動網絡帶寬,較大的安裝包給玩家設置了較高的門檻,因此目前的手遊產品也越來越多的考慮微端方案。即安裝包只包含部分遊戲關卡,或者只作爲一個下載器,而完整的遊戲資源放在CDN資源服務器上,然後按需下載,這也是一般頁遊的思路。這種情況下,我們對比了幾種打包機制給大家參考。

測試數據稍後提供

附錄1:斷線重連流程圖

附錄2:RSSI信號強度分級

 

1、弱網絡下的斷線重連

玩家在遊戲過程中,所處的網絡環境是複雜多變的,可能是wifi的網絡不穩定,或處在3G甚至2G的環境下等。在這些情況下,網絡遊戲會由於網絡或包量等原因而出現延遲,拉拽,甚至掉線等問題。對於這些問題,一方面要對程序的包量和通信進行優化,從根本上減緩網絡壓力。另一方面,在出現網絡異常的時候,保證玩家能重新連接到服務器並繼續遊戲,並且體驗良好。

網絡的“弱”主要體現在延遲和丟包率大兩方面,而這兩方面都會影響遊戲的體驗。我們在市區低速移動的網絡情況下(丟包率10%, 平均延遲890ms)測試,並對此情況下進行分析優化,達到了玩家能夠順利遊戲的體驗。

由斷線或網絡異常性質決定,基本上都是首先由客戶端感知,因此斷線重連的機制主要是由客戶端來進行發起。

下面我主要從客戶端方向就斷線重連觸發的條件,如何重連,以及重連後的後續處理三個方面來闡述,最後簡略分析一下對我們遊戲客戶端容易掉線的一些思考。

2、判斷重連條件

在弱網絡條件下,我們根據網絡狀況的不同,有兩種情況觸發斷線重連。

網絡條件異常

在弱網絡情況下,網絡會顯式的拋出一些異常,大部分情況下是NetworkException,少部分情況是Timeout(當然還有連接關閉等等其他異常,就不一一贅述)。在這種顯式拋出異常的情況下,就說明網絡已經無法順利的和服務器進行連接,在這些消息類型中,對於客戶端斷網或網絡波動導致的原因,客戶端這邊就會觸發斷線重連流程。

心跳包觸發以及觸發時間的確定

上一種情況的觸發條件是客戶端手機本身斷網或網絡發生異常的情況的觸發,但實際情況中,還有可能發生客戶端網絡並未斷開,也並沒有異常拋出,但是卻出現客戶端和服務器無法正常進行收發消息的情況。

這種情況一方面原因是中間鏈路的連接異常,另一方面也會由於延遲過高或丟包導致的TCP重發造成的延遲過大,影響到服務器和客戶端之間正常的收發消息。

市區低速移動的網絡的模擬測試中,我們收集到的最大心跳包延遲是10s左右,也就是說,在此“弱”網絡情況下,網絡延遲峯值大概有10s以上。因此,我們對心跳包在一定時間內如果沒有收到返回包的情況下也認爲是一種掉線情況,會觸發斷線重連處理,目前在大廳設置的觸發時間是30s,戰鬥中觸發的時間是20s。

遊戲切出

有一種情況是由於客戶端切出遊戲,或者中間接到電話等導致遊戲暫停等情況,在一定時間後服務器會主動斷開和客戶端的連接,客戶端也需要主動觸發重連。

3、斷線重連的大致流程圖

斷線重連收到網絡異常消息階段處理流程:

斷線重連結果處理階段:

4、對流程圖的補充說明

在重連過程中,如果收到客戶端主動斷開的消息,會屏蔽所有重連行爲

由於在收到NetworkException的時候無法保證網絡狀態,如果此時網絡已經連接上,會無法觸發後續重連過程,所以會在NetworkException的時候double check一下是否連接到網絡。

5、關於狀態機:

斷線重連並不是一個瞬間操作,而是一個過程。在整個斷線重連的過程中,存在着一個個階段,也就對應一個個的狀態。初步來說,主要分爲以下幾個階段。

A. Start:網絡正常狀態,簡稱S

B. Wait:網絡已經斷開,等待網絡恢復,簡稱W

C. Reconnect:重新連接狀態,簡稱R

D. End: 重新連接失敗,簡稱E

狀態轉換圖見下:

6、重連後的相關處理

在程序斷線重連的過程中除非重連失敗,否則最理想的情況是希望玩家在斷線前後無感知,可以流暢的繼續遊戲而不受到斷線的影響。

1 對於大廳的後續處理

A.拉取相關屬性和物品。再重新連接後,由於在斷開過程中可能會有相關數據的變化,會拉取人物相關屬性和物品

B.重發斷線前的相關請求:這個和具體的系統相關,如果斷線前的系統進行的是一些對數據敏感的操作,比如合成物品,購買物品等,在發起的時候會做無法二次點擊的處理並加入到重發列表中,在網絡恢復之後重發。此時如果服務器未做處理便會直接處理,如果做了處理需要服務器忽略(注,這個需要服務器配合)

2對於戰鬥的後續處理

A.重新拉取戰鬥狀態數據:這個是由於我們遊戲是對戰鬥實時性要求較高的遊戲,所以在斷線過程中的戰鬥狀態可能會發生很大的改變,這些改變必須需要重新同步,比如可能會死亡,球變大或變小,位置改變等都有可能,所以在重連之後,我們是全量拉取玩家戰鬥數據,同步到最新的狀態。

7、對重連的一些說明

在戰鬥過程中,其實還伴隨這大廳這個連接,所以很多情況下,戰鬥連接的斷開也會伴隨着大廳連接的同時斷開。對此,我們對於不同連接建立不同的重連器,從而達到兩個連接相互獨立,無論只是單個連接的斷開還是兩者同時斷開,都不會相互影響,各自走各自的重連過程。

8、對之前版本遊戲更加容易掉線的一些思考

雖然其實很多時候確實是wifi不穩定導致的網絡問題,但之前版本確實比其他遊戲更容易掉線,具體體現在在同一個網絡下,兩個差不多的手機,玩我們遊戲的時候掉線的頻率更高,對此以下是我的一些想法。

對於網絡經常觸發異常的原因,除了網絡本身的不穩定外,主要還是TCP協議中,客戶端緩衝區在網絡不穩定的時候容易寫滿導致的問題。

對於這個問題,一方面可以適當的擴大緩衝區的大小,對此把客戶端網絡的緩衝區擴大,從1024*100,擴大到1024*2000,也確實改善了遊戲的網絡狀況。

但這種方式只是並沒有從本質上解決這個問題,網絡其實的壓力還是很大,流量過大也是我們遇到的問題之一。

由於包頭和TCP持續計時器的原因,在每個包的包頭都會有一些不屬於遊戲協議內容的造成的流量,對於一些能夠合併到一起發送的小包,合併小包和減少包量可以很大幅度的減少流量。而且也容易避免由於滑動窗口可發送部分的迅速充滿導致的網絡擁塞。

另一方面,單個包的大小過大也會迅速的撐大緩衝區,而且在傳輸過程中造成傳輸峯值,造成網絡延遲,拆分過大的包,比如一瞬間全量拉取排行榜等的數據通過分批拉取,減緩網絡壓力,也能達到優化網絡的目的。

9、對於爲什麼會有wait狀態

其實對於一般的想法來說,其實斷線重連只需要Start,Reconnect,End三種狀態,確實,這三種狀態可以把整個斷線重連的過程完成,對於wait,主要一下幾個原因。

Wait 狀態和Reconnect狀態的區別在於Wait狀態手機網絡並沒有連接,而Reconnect狀態的網絡已經恢復了,這個其實是有差別的,可以對網絡的狀態進行不同的處理。

因爲由於一些原因(比如在wait狀態可能由於Apollo錯誤原因而無法收到網絡恢復的消息等)我們也低頻嘗試了重新和服務器建立連接,但是其目的是發現是否能夠建立連接,更多的時候會返回失敗的消息,是一種double check 的保證策略,而Reconnect狀態下的重連是我們知道了網絡已經恢復,嘗試去連接服務器,目的是爲了真正的建立連接,這兩種情況無論在目的上還是在連接的頻率上都有差別,而且將兩個狀態區分便於我們在不同狀態下做不同處理。



作者:CatherinePlans
鏈接:https://www.jianshu.com/p/110d1f0b457d
來源:簡書
簡書著作權歸作者所有,任何形式的轉載都請聯繫作者獲得授權並註明出處。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章