移動平台下的Socket幾個問題


在頁游時代,使用Flash ActionScript 3.0進行開發,as3提供比較簡單和健全的socket API。到了手游時代,基於tcp的socket編程遇到了一些棘手的問題。通常情況下手游都要支持至少二大主流平台:Android、IOS,二者共存,暫時沒有跡象表現哪一方會沒落。

 

頁游跑在瀏覽器里,所有的連接成功、失敗等操作,都可以通過addEventListener進行監聽,很方便,一般也不存在頻繁掉線的情況。而手游,因為手機的便攜性決定了它的移動性,既然是可移動的那就會一定會面臨網絡不穩定的情況。

 

client與server通信如果使用TCP邏輯會比較簡單一些,但存在一些問題,這個問題在移動平台下暴露的比較明顯。QQ客戶端使用的是UDP而非TCP,主要原因是因為網絡的不穩定性。而TCP和UDP主要區別是什么呢?其實就是長連接與短連接的區別

 

長連接是比較消耗資源的,但是通常情況下,一方斷了另一方會較為及時的收到消息,業務邏輯上是比較簡單和及時的。

 

基於TCP的Socket網絡編程,如果想跨平台,通常都使用C/C++進行封裝,這樣代碼層面至少是統一了。但移動設備上面臨的主要問題是頻繁的掉線,Android好一點,IOS其實是比較麻煩的。下面列一下在Android、IOS設備上HOME、電源鍵對網絡的影響:

 

平台 Home鍵切后(網絡狀態) 電源鍵(網絡狀態)
Android Y Y
IOS Y N

其它的2G/3G/4G/Wifi之間的相互切換,也是比較麻煩,必須要重連了(因為客戶端的IP已經發生變化了)。

 

電源鍵按下時,IOS就鎖屏了。Socket就斷掉了,但Server端並不會收到Client掉線。問題來了,不是說TCP是長連接嗎,我一端掉了那另一端應該收到斷開的消息啊,嗯,理論上是這樣子的,協議也是這么規定的,但要先注意這樣一個問題:

TCP連接使用的是三次握手

TCP斷開使用的是四次握手

連接使用三次握手,這個不多說了,主要原因是為了保證二端都能確認連接已經建立(SYN、ACK)。而斷開為什么是四次?因為socket是雙工(雙向通信),相當於存在二條通訊的線路,一條用於接收,一條用於發送。一方主動關閉時(寫通道被關閉了,但此時讀通道還是正常的),它會發送FIN,另一端收到時會響應FIN+1(表示我收到你的關閉請求啦~),然后另一端處理完自己的邏輯后,告訴發起請求關閉的一方,我同意了你的關閉請求(不會再向你發送數據啦~),此時發起關閉的一方的讀通道才是正常被關閉了。發起請求關閉的一方會在2MSL(報文最長生命周期的兩倍 Maximum Segment Lifetime)后釋放掉它所占用的端口(連接記錄此時才會被清除)。

 

所以,你會發現哇,原來關閉也是需要確認的。假設服務器突然斷電了,客戶端是不知道服務器端已經無法連接了的,還會認為可以發送數據給服務器端。通常都是使用心跳包進行檢測來雙方的連接是否還存在。

 

我嘗試過在cocos2dx使用libuv來實現網絡通信,感覺異步寫起來確實過於繁瑣。libuv采用異步回調的寫法,所有的回調函數必須是static的。通常一款游戲是有二個socket長連接的:游戲主邏輯、聊天服務器,好在libuv支持回調參數里“夾帶自定義參數”,倒也問題不大。不過我遇到一件奇葩的事情是,在三星GTI9000 Android 2.3.6系統上,將游戲切入后台,網絡狀態由2G變成wifi,不回調socket,調用發送之后也沒有觸發關閉回調方法,其它能借用到的Android設備都測試過,沒什么問題了。wifi切到2G/3G,后台切換至前台后立馬觸發關閉的回調函數。

 

后端處理是這樣的,建立socket時會隨機生成一個密鑰串,當客戶端斷開連接時,拿這個密鑰串向服務器進行驗證,但是服務器驗證時有個特殊的判定,如果請求生成密鑰串的客戶端IP與重連時的客戶端IP不一致,則認為是非法請求。也就是說2G切換至WIFI時,IP變了,服務器其實是直接將連接斷開了,但為什么沒觸發關閉的回調函數,這個或許是那個Android系統版本的bug吧

 

后來想的辦法有二個:

1、針對Android平台,記錄連接時的網絡類型,然后切換至前台時再獲取網絡類型,如果發現二次的網絡類型不一致就提示需要重新登錄游戲了;

2、記錄建立連接時的IP地址,當切換至前台再獲取IP,如果這二個IP不致,也認為是需要重登錄游戲了,因為無論你拿什么密鑰串都將無法再登錄游戲,服務器認為這個請求是非法的;


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM