基于cocos2d-x引擎游戲網(wǎng)絡(luò)安全處理(C++環(huán)境)

【原創(chuàng)博文,轉(zhuǎn)載請注明出處!】
前段時間棋牌游戲在弱網(wǎng)環(huán)境下奔潰率比較高,綜合各種測試環(huán)境和奔潰日志,比較多見的情況是:弱網(wǎng)下離開當(dāng)前的界面后,當(dāng)前界面的網(wǎng)絡(luò)請求才回調(diào)過來刷新UI。與iOS 原生開發(fā)UIViewController不同的是,Cocos2d-x 引擎中c++環(huán)境下創(chuàng)建的類的回收是在析構(gòu)函數(shù)執(zhí)行完之后的某個合理時間才會進(jìn)行。所以,離開當(dāng)前的Scene或Layer等經(jīng)常發(fā)起網(wǎng)絡(luò)請求的地方,回調(diào)回來后,本質(zhì)上Scene已經(jīng)被銷毀了,但是內(nèi)存還在,因此在回調(diào)刷新UI的時候,因為內(nèi)部控件被銷毀造成各種野指針奔潰。

解決辦法:構(gòu)造了一個網(wǎng)絡(luò)工具安全助手。

工具類的3個重量級方法:

/**
 將發(fā)起請求的類名加入注冊池
 node : 當(dāng)前調(diào)用的類對象(取對象的地址作為唯一標(biāo)識符)
 */
static void registerClassName(Node *node);

/**
 將發(fā)起請求的類名移出注冊池
 node : 當(dāng)前調(diào)用的類對象(取對象的地址作為唯一標(biāo)識符)
 */
static void unregisterClassName(Node *node);

/**
 是否需要進(jìn)行網(wǎng)絡(luò)請求回調(diào)
 node : 當(dāng)前調(diào)用的類對象(取對象的地址作為唯一標(biāo)識符)
 */
static bool needCallback(Node *node);

思路:
Step 1:在類的 onEnter();方法里面調(diào)用 static void registerClassName(Node *node); 注冊。
Step 2:在類的 onExit();方法里面調(diào)用static void unregisterClassName(Node *node); 解注冊。
Step 3:在網(wǎng)絡(luò)請求回調(diào)處調(diào)用static bool needCallback(Node *node); 攔截,如果那個類不存在了,回調(diào)就直接pass掉,否則就放過它。

涉及到如何選擇唯一標(biāo)識符的問題,也就是上述方法中的node。
參考cocos2d引擎,發(fā)現(xiàn)官方有使用其類的內(nèi)存地址作為唯一ID,覺得很棒。
string className = StringUtils::format("%p",node);
之前我們選擇類名作為ID,這樣在弱網(wǎng)下還會存在一個bug:如果用戶手速快,前后兩次進(jìn)入同一個layer,由于標(biāo)識符取了類名,所以這兩次肯定相同,所以不會攔截前一次的回調(diào),然后再刷新UI,(前一次的子控件實際上已經(jīng)銷毀了)然后就creash.

唯一標(biāo)識符選擇當(dāng)前類在內(nèi)存中的地址,很安全!想一下系統(tǒng)先創(chuàng)建類A,然后創(chuàng)建類B,再銷毀類A,這個時候B和A的內(nèi)存地址相同的概率有多大?
(先創(chuàng)建類A,然后創(chuàng)建類B,再銷毀類A)。
(先創(chuàng)建類A,然后創(chuàng)建類B,再銷毀類A)。
(先創(chuàng)建類A,然后創(chuàng)建類B,再銷毀類A)。

B和A的內(nèi)存地址還可以相同???

miaowu....jpg

下面讓我們一起來看看這個網(wǎng)絡(luò)安全助手的實現(xiàn)細(xì)節(jié)吧:


//
//  SafeNetworkHandler.cpp
//  HelloCpp-mobile
//
//  Created by RephontilZhou on 2018/3/20.
//

#include "SafeNetworkHandler.hpp"

static SafeNetworkHandler *singleInstance = nullptr;

void SafeNetworkHandler::init()
{
    if (!singleInstance) {
        singleInstance = new SafeNetworkHandler();
    }
}

/**
 將發(fā)起請求的類名加入注冊池
 node : 當(dāng)前調(diào)用的類對象(取對象的地址作為唯一標(biāo)識符)
 */
void SafeNetworkHandler::registerClassName(Node *node)
{
    init();
    string className = StringUtils::format("%p",node);
    singleInstance->classNameList.push_back(className);
}

/**
 將發(fā)起請求的類名移出注冊池
 node : 當(dāng)前調(diào)用的類對象(取對象的地址作為唯一標(biāo)識符)
 */
void SafeNetworkHandler::unregisterClassName(Node *node)
{
    string className = StringUtils::format("%p",node);
    if (singleInstance->classNameList.size() > 0)
    {
        for (vector<string>::iterator it = singleInstance->classNameList.begin(); it != singleInstance->classNameList.end();)
        {
            if ((*it) == className) {
                it = singleInstance->classNameList.erase(it);
            }
            else {
                it++;
            }
        }
    }
}

/**
 是否需要進(jìn)行請求回調(diào)
 node : 當(dāng)前調(diào)用的類對象(取對象的地址作為唯一標(biāo)識符)
 */
bool SafeNetworkHandler::needCallback(Node *node)
{
    string className = StringUtils::format("%p",node);
    bool enable = false;
    if (singleInstance->classNameList.size() > 0)
    {
        for (vector<string>::iterator it = singleInstance->classNameList.begin(); it != singleInstance->classNameList.end(); ++it) {
            if ((*it) == className) {
                enable = true;
            }
            
        }
    }
    
    return enable;
}

好啦,簡書上面的第一篇技術(shù)分享到此結(jié)束啦,如果此時您正好也使用cocos2d-X的引擎開發(fā)游戲,碰巧在網(wǎng)絡(luò)請求中遇到同樣棘手的問題,那么上面的解決方案肯定能讓你笑得像菊花一樣地燦爛。

看到這里,點個贊唄??.png
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容