欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

CocosCreator通用框架設(shè)計(jì)之網(wǎng)絡(luò)

 更新時(shí)間:2021年04月14日 11:05:21   作者:weixin_39752434  
這篇文章主要介紹了CocosCreator通用框架設(shè)計(jì)之網(wǎng)絡(luò),詳細(xì)講解了WebSocket的原理和使用方法,對(duì)WebSocket感興趣的同學(xué),一定要看一下

前言

在 Cocos Creator 中發(fā)起一個(gè) http 請(qǐng)求是比較簡(jiǎn)單的,但很多游戲希望能夠和服務(wù)器之間保持長(zhǎng)連接,以便服務(wù)端能夠主動(dòng)向客戶端推送消息,而非總是由客戶端發(fā)起請(qǐng)求,對(duì)于實(shí)時(shí)性要求較高的游戲更是如此。這里我們會(huì)設(shè)計(jì)一個(gè)通用的網(wǎng)絡(luò)框架,可以方便地應(yīng)用于我們的項(xiàng)目中。

使用websocket

在實(shí)現(xiàn)這個(gè)網(wǎng)絡(luò)框架之前,我們先了解一下 websocket。websocket 是一種基于 tcp 的全雙工網(wǎng)絡(luò)協(xié)議,可以讓網(wǎng)頁(yè)創(chuàng)建持久性的連接,進(jìn)行雙向的通訊。在 Cocos Creator 中使用 websocket 既可以用于 H5 網(wǎng)頁(yè)游戲上,同樣支持原生平臺(tái) Android 和 iOS。

構(gòu)造 websocket 對(duì)象

在使用 websocket 時(shí),第一步應(yīng)該創(chuàng)建一個(gè) websocket 對(duì)象。websocket 對(duì)象的構(gòu)造函數(shù)可以傳入2個(gè)參數(shù),第一個(gè)是 url 字符串,第二個(gè)是協(xié)議字符串或字符串?dāng)?shù)組,指定了可接受的子協(xié)議,服務(wù)端需要選擇其中的一個(gè)返回,才會(huì)建立連接,但我們一般用不到。

url 參數(shù)非常重要,主要分為4部分:協(xié)議、地址、端口、資源。

比如 ws://echo.websocket.org:

  • 協(xié)議:必選項(xiàng),默認(rèn)是 ws 協(xié)議,如果需要安全加密則使用 wss。
  • 地址:必選項(xiàng),可以是 ip 或域名,當(dāng)然建議使用域名。
  • 端口:可選項(xiàng),在不指定的情況下,ws 的默認(rèn)端口為 80,wss 的默認(rèn)端口為 443。
  • 資源:可選性,一般是跟在域名后某資源路徑,我們基本不需要它。

websocket 的狀態(tài)

websocket 有4個(gè)狀態(tài),可以通過(guò) readyState 屬性查詢:

  • 0 CONNECTING 尚未建立連接。
  • 1 OPEN WebSocket連接已建立,可以進(jìn)行通信。
  • 2 CLOSING 連接正在進(jìn)行關(guān)閉握手,或者該close()方法已被調(diào)用。
  • 3 CLOSED 連接已關(guān)閉。

websocket 的 API

websocket 只有2個(gè) API,void send( data ) 發(fā)送數(shù)據(jù)和 void close( code, reason ) 關(guān)閉連接。

send 方法只接收一個(gè)參數(shù)——即要發(fā)送的數(shù)據(jù),類型可以是以下4個(gè)類型的任意一種:string | ArrayBufferLike | Blob | ArrayBufferView。

如果要發(fā)送的數(shù)據(jù)是二進(jìn)制,我們可以通過(guò) websocket 對(duì)象的 binaryType 屬性來(lái)指定二進(jìn)制的類型,binaryType 只可以被設(shè)置為“blob”或“arraybuffer”,默認(rèn)為“blob”。如果我們要傳輸?shù)氖俏募@樣較為固定的、用于寫入到磁盤的數(shù)據(jù),使用 blob。而你希望傳輸?shù)膶?duì)象在內(nèi)存中進(jìn)行處理則使用較為靈活的 arraybuffer。如果要從其他非 blob 對(duì)象和數(shù)據(jù)構(gòu)造一個(gè) blob,需要使用 blob 的構(gòu)造函數(shù)。

在發(fā)送數(shù)據(jù)時(shí),官方有2個(gè)建議:

  • 檢測(cè) websocket 對(duì)象的 readyState 是否為 OPEN,是才進(jìn)行 send。
  • 檢測(cè) websocket 對(duì)象的 bufferedAmount 是否為0,是才進(jìn)行 send(為了避免消息堆積,該屬性表示調(diào)用 send 后堆積在 websocket 緩沖區(qū)的還未真正發(fā)送出去的數(shù)據(jù)長(zhǎng)度)。

close 方法接收2個(gè)可選的參數(shù),code 表示錯(cuò)誤碼,我們應(yīng)該傳入 1000 或 3000~4999 之間的整數(shù),reason 可以用于表示關(guān)閉的原因,長(zhǎng)度不可超過(guò) 123 字節(jié)。

websocket 的回調(diào)

websocket 提供了4個(gè)回調(diào)函數(shù)供我們綁定:

  • onopen:連接成功后調(diào)用。
  • onmessage:有消息過(guò)來(lái)時(shí)調(diào)用:傳入的對(duì)象有 data 屬性,可能是字符串、blob 或 arraybuffer。
  • onerror:出現(xiàn)網(wǎng)絡(luò)錯(cuò)誤時(shí)調(diào)用:傳入的對(duì)象有 data 屬性,通常是錯(cuò)誤描述的字符串。
  • onclose:連接關(guān)閉時(shí)調(diào)用:傳入的對(duì)象有 code、reason、wasClean 等屬性。

注意:當(dāng)網(wǎng)絡(luò)出錯(cuò)時(shí),會(huì)先調(diào)用 onerror 再調(diào)用 onclose,無(wú)論何種原因的連接關(guān)閉,onclose 都會(huì)被調(diào)用。

Echo 實(shí)例

下面 websocket 官網(wǎng)的 echo demo 的代碼,可以將其寫入一個(gè) html 文件中并用瀏覽器打開,打開后會(huì)自動(dòng)創(chuàng)建 websocket 連接,在連接上時(shí)主動(dòng)發(fā)送了一條消息“WebSocket rocks”,服務(wù)器會(huì)將該消息返回,觸發(fā) onMessage,將信息打印到屏幕上,然后關(guān)閉連接。具體可以參考:http://www.websocket.org/echo.html17 

默認(rèn)的 url 前綴是wss,由于 wss 抽風(fēng),使用 ws 才可以連接上,如果 ws 也抽風(fēng),可以試試連這個(gè)地址ws://121.40.165.18:8800,這是國(guó)內(nèi)的一個(gè)免費(fèi)測(cè)試 websocket 的網(wǎng)址。

 設(shè)計(jì)框架

一個(gè)通用的網(wǎng)絡(luò)框架,在通用的前提下還需要能夠支持各種項(xiàng)目的差異需求,根據(jù)經(jīng)驗(yàn),常見的需求差異如下:

  • 用戶協(xié)議差異,游戲可能傳輸 json、protobuf、flatbuffer 或者自定義的二進(jìn)制協(xié)議。
  • 底層協(xié)議差異,我們可能使用 websocket、或者微信小游戲的 wx.websocket、甚至在原生平臺(tái)我們希望使用 tcp/udp/kcp 等協(xié)議。
  • 登陸認(rèn)證流程,在使用長(zhǎng)連接之前我們理應(yīng)進(jìn)行登陸認(rèn)證,而不同游戲登陸認(rèn)證的方式不同。
  • 網(wǎng)絡(luò)異常處理,比如超時(shí)時(shí)間是多久,超時(shí)后的表現(xiàn)是怎樣的,請(qǐng)求時(shí)是否應(yīng)該屏蔽 UI 等待服務(wù)器響應(yīng),網(wǎng)絡(luò)斷開后表現(xiàn)如何,自動(dòng)重連還是由玩家點(diǎn)擊重連按鈕進(jìn)行重連,重連之后是否重發(fā)斷網(wǎng)期間的消息?等等這些。
  • 多連接的處理,某些游戲可能需要支持多個(gè)不同的連接,一般不會(huì)超過(guò)2個(gè),比如一個(gè)主連接負(fù)責(zé)處理大廳等業(yè)務(wù)消息,一個(gè)戰(zhàn)斗連接直接連戰(zhàn)斗服務(wù)器,或者連接聊天服務(wù)器。

根據(jù)上面的這些需求,我們對(duì)功能模塊進(jìn)行拆分,盡量保證模塊的高內(nèi)聚,低耦合。

ProtocolHelper 協(xié)議處理模塊——當(dāng)我們拿到一塊 buffer時(shí),我們可能需要知道這個(gè) buffer 對(duì)應(yīng)的協(xié)議或者 id 是多少,比如我們?cè)谡?qǐng)求的時(shí)候就傳入了響應(yīng)的處理回調(diào),那么常用的做法可能會(huì)用一個(gè)自增的 id 來(lái)區(qū)別每一個(gè)請(qǐng)求,或者是用協(xié)議號(hào)來(lái)區(qū)分不同的請(qǐng)求,這些是開發(fā)者需要實(shí)現(xiàn)的。我們還需要從 buffer 中獲取包的長(zhǎng)度是多少?包長(zhǎng)的合理范圍是多少?心跳包長(zhǎng)什么樣子等等。

Socket 模塊——實(shí)現(xiàn)最基礎(chǔ)的通訊功能,首先定義 Socket 的接口類 ISocket,定義如連接、關(guān)閉、數(shù)據(jù)接收與發(fā)送等接口,然后子類繼承并實(shí)現(xiàn)這些接口。

NetworkTips 網(wǎng)絡(luò)顯示模塊——實(shí)現(xiàn)如連接中、重連中、加載中、網(wǎng)絡(luò)斷開等狀態(tài)的顯示,以及 UI 的屏蔽。

NetNode 網(wǎng)絡(luò)節(jié)點(diǎn)——所謂網(wǎng)絡(luò)節(jié)點(diǎn),其實(shí)主要的職責(zé)是將上面的功能串聯(lián)起來(lái),為用戶提供一個(gè)易用的接口。

NetManager 管理網(wǎng)絡(luò)節(jié)點(diǎn)的單例——我們可能有多個(gè)網(wǎng)絡(luò)節(jié)點(diǎn)(多條連接),所以這里使用單例來(lái)進(jìn)行管理,使用單例來(lái)操作網(wǎng)絡(luò)節(jié)點(diǎn)也會(huì)更加方便。

ProtocolHelper

在這里定義了一個(gè) IProtocolHelper 的簡(jiǎn)單接口,如下所示:

export type NetData = (string | ArrayBufferLike | Blob | ArrayBufferView);// 協(xié)議輔助接口
export interface IProtocolHelper
{    
    getHeadlen(): number;                   // 返回包頭長(zhǎng)度    
    getHearbeat(): NetData;                 // 返回一個(gè)心跳包    
    getPackageLen(msg: NetData): number;    // 返回整個(gè)包的長(zhǎng)度    
    checkPackage(msg: NetData): boolean;    // 檢查包數(shù)據(jù)是否合法    
    getPackageId(msg: NetData): number;     // 返回包的id或協(xié)議類型
}

Socket

在這里定義了一個(gè) ISocket 的簡(jiǎn)單接口,如下所示:

// Socket接口
export interface ISocket {    
    onConnected: (event) => void;                 //連接回調(diào) 
    onMessage: (msg: NetData) => void;            // 消息回調(diào)    
    onError: (event) => void;                     // 錯(cuò)誤回調(diào)    
    onClosed: (event) => void;                    // 關(guān)閉回調(diào)    
    connect(ip: string, port: number);            // 連接接口    
    send(buffer: NetData);                        // 數(shù)據(jù)發(fā)送接口    
    close(code?: number, reason?: string);        // 關(guān)閉接口
}

接下來(lái)我們實(shí)現(xiàn)一個(gè) WebSock,繼承于 ISocket,我們只需要實(shí)現(xiàn) connect、send 和 close 接口即可。send 和 close 都是對(duì) websocket 對(duì)簡(jiǎn)單封裝,connect 則需要根據(jù)傳入的 ip、端口等參數(shù)構(gòu)造一個(gè) url 來(lái)創(chuàng)建 websocket,并綁定 websocket 的回調(diào)。

export class WebSock implements ISocket {    
    private _ws: WebSocket = null;              // websocket對(duì)象   
    onConnected: (event) => void = null;    
    onMessage: (msg) => void = null;    
    onError: (event) => void = null;    
    onClosed: (event) => void = null;   
    connect(options: any) {        
    if (this._ws) {            
        if (this._ws.readyState === WebSocket.CONNECTING) {                
            console.log("websocket connecting, wait for a moment...")                
            return false;
        }
    }
    let url = null;        
    if(options.url) {           
        url = options.url;        
    } else {            
        let ip = options.ip;            
        let port = options.port;            
        let protocol = options.protocol;            
        url = `${protocol}://${ip}:${port}`;           
    }        
        this._ws = new WebSocket(url);       
        this._ws.binaryType = options.binaryType ? options.binaryType : "arraybuffer";        
        this._ws.onmessage = (event) => {           
        this.onMessage(event.data);        
    };        
        this._ws.onopen = this.onConnected;        
        this._ws.onerror = this.onError;        
        this._ws.onclose = this.onClosed;       
        return true;    
    }    
    send(buffer: NetData) {        
    if (this._ws.readyState == WebSocket.OPEN)  {           
        this._ws.send(buffer);           
        return true;       
    }       
    return false;    
    }    
    close(code?: number, reason?: string) {        
    this._ws.close();    
    }
}

NetworkTips

INetworkTips 提供了非常的接口,重連和請(qǐng)求的開關(guān),框架會(huì)在合適的時(shí)機(jī)調(diào)用它們,我們可以繼承 INetworkTips 并定制我們的網(wǎng)絡(luò)相關(guān)提示信息,需要注意的是這些接口可能會(huì)被**多次調(diào)用**。

// 網(wǎng)絡(luò)提示接口
export interface INetworkTips {    
    connectTips(isShow: boolean): void;    
    reconnectTips(isShow: boolean): void;    
    requestTips(isShow: boolean): void;
}

NetNode

NetNode 是整個(gè)網(wǎng)絡(luò)框架中最為關(guān)鍵的部分,一個(gè) NetNode 實(shí)例表示一個(gè)完整的連接對(duì)象,基于 NetNode 我們可以方便地進(jìn)行擴(kuò)展,它的主要職責(zé)有:

連接維護(hù)

  • 連接的建立與鑒權(quán)(是否鑒權(quán)、如何鑒權(quán)由用戶的回調(diào)決定)
  • 斷線重連后的數(shù)據(jù)重發(fā)處理
  • 心跳機(jī)制確保連接有效(心跳包間隔由配置,心跳包的內(nèi)容由ProtocolHelper定義)
  • 連接的關(guān)閉

數(shù)據(jù)發(fā)送

  • 支持?jǐn)嗑€重傳,超時(shí)重傳
  • 支持唯一發(fā)送(避免同一時(shí)間重復(fù)發(fā)送)

數(shù)據(jù)接收

  • 支持持續(xù)監(jiān)聽
  • 支持request-respone模式

界面展示

  • 可自定義網(wǎng)絡(luò)延遲、短線重連等狀態(tài)的表現(xiàn)
  • 首先我們定義了 NetTipsType、NetNodeState 兩個(gè)枚舉,以及 NetConnectOptions 結(jié)構(gòu)供 NetNode 使用。
  • 接下來(lái)是 NetNode 的成員變量,NetNode 的變量可以分為以下幾類:
  • NetNode 自身的狀態(tài)變量,如 ISocket 對(duì)象、當(dāng)前狀態(tài)、連接參數(shù)等等。
  • 各種回調(diào),包括連接、斷開連接、協(xié)議處理、網(wǎng)絡(luò)提示等回調(diào)。
  • 各種定時(shí)器,如心跳、重連相關(guān)的定時(shí)器。
  • 請(qǐng)求列表與監(jiān)聽列表,都是用于接收到的消息處理。

接下來(lái)介紹網(wǎng)絡(luò)相關(guān)的成員函數(shù),首先看初始化與:

  • init 方法用于初始化 NetNode,主要是指定 Socket 與協(xié)議等處理對(duì)象。
  • connect 方法用于連接服務(wù)器。
  • initSocket 方法用于綁定 Socket 的回調(diào)到 NetNode 中。
  • updateNetTips 方法用于刷新網(wǎng)絡(luò)提示。

onConnected 方法在網(wǎng)絡(luò)連接成功后調(diào)用,自動(dòng)進(jìn)入鑒權(quán)流程(如果設(shè)置了_connectedCallback),在鑒權(quán)完成后需要調(diào)用 onChecked 方法使 NetNode 進(jìn)入可通訊的狀態(tài),在未鑒權(quán)的情況,我們不應(yīng)該發(fā)送任何業(yè)務(wù)請(qǐng)求,但登錄驗(yàn)證這類請(qǐng)求應(yīng)該發(fā)送給服務(wù)器,這類請(qǐng)求可以通過(guò)帶force參數(shù)強(qiáng)制發(fā)送給服務(wù)器。

接收到任何消息都會(huì)觸發(fā) onMessage,首先會(huì)對(duì)數(shù)據(jù)包進(jìn)行校驗(yàn),校驗(yàn)的規(guī)則可以在自己的 ProtocolHelper 中實(shí)現(xiàn),如果是一個(gè)合法的數(shù)據(jù)包,我們會(huì)將心跳和超時(shí)計(jì)時(shí)器進(jìn)行更新——重新計(jì)時(shí),最后在 _requests 和 _listener 中找到該消息的處理函數(shù),這里是通過(guò) rspCmd 進(jìn)行查找的,rspCmd 是從 ProtocolHelper 的 getPackageId 取出的,我們可以將協(xié)議的命令或者序號(hào)返回,由我們自己來(lái)決定請(qǐng)求和響應(yīng)如何對(duì)應(yīng)。

onError 和 onClosed 是網(wǎng)絡(luò)出錯(cuò)和關(guān)閉時(shí)調(diào)用的,無(wú)論是否出錯(cuò),最終都會(huì)調(diào)用 onClosed,在這里我們執(zhí)行斷線回調(diào),以及做自動(dòng)重連的處理。當(dāng)然也可以調(diào)用 close來(lái)關(guān)閉套接字。close 與 closeSocket 的區(qū)別在于 closeSocket 只是關(guān)閉套接字——我仍然要使用當(dāng)前的 NetNode,可能通過(guò)下一次 connect 恢復(fù)網(wǎng)絡(luò)。而 close則是清除所有的狀態(tài)。

發(fā)起網(wǎng)絡(luò)請(qǐng)求有3種方式:

send 方法,純粹地發(fā)送數(shù)據(jù),如果當(dāng)前斷網(wǎng)或者驗(yàn)證中會(huì)進(jìn)入 _request 隊(duì)列。

request 方法,在請(qǐng)求的時(shí)候即以閉包的方式傳入回調(diào),在該請(qǐng)求的響應(yīng)回到時(shí)會(huì)執(zhí)行回調(diào),如果同時(shí)有多個(gè)相同的請(qǐng)求,那么這 N 個(gè)請(qǐng)求的響應(yīng)會(huì)依次回到客戶端,響應(yīng)回調(diào)也會(huì)依次執(zhí)行(每次只會(huì)執(zhí)行一個(gè)回調(diào))。

requestUnique 方法,如果我們不希望有多個(gè)相同的請(qǐng)求,可以使用 requestUnique 來(lái)確保每一種請(qǐng)求同時(shí)只會(huì)有一個(gè)。

這里確保沒(méi)有重復(fù)之所以使用的是遍歷 _requests,是因?yàn)槲覀儾粫?huì)積壓大量的請(qǐng)求到 _requests中,超時(shí)或異常重發(fā)也不會(huì)導(dǎo)致 _requests 的積壓,因?yàn)橹匕l(fā)的邏輯是由 NetNode 控制的,而且在網(wǎng)絡(luò)斷開的情況下,我們理應(yīng)屏蔽用戶發(fā)起請(qǐng)求,此時(shí)一般會(huì)有一個(gè)全屏遮罩——網(wǎng)絡(luò)出現(xiàn)波動(dòng)之類的提示。

我們有2種回調(diào),一種是前面的 request 回調(diào),這種回調(diào)是臨時(shí)性的,一般隨著請(qǐng)求-響應(yīng)-執(zhí)行而立即清理,_listener 回調(diào)則是常駐的,需要我們手動(dòng)管理的,比如打開某界面時(shí)監(jiān)聽、離開是關(guān)閉,或者在游戲一開始就進(jìn)行監(jiān)聽。適合處理服務(wù)器的主動(dòng)推送消息。

最后是心跳與超時(shí)相關(guān)的定時(shí)器,我們每隔 _heartTime 會(huì)發(fā)送一個(gè)心跳包,每隔 _receiveTime 檢測(cè)如果沒(méi)有收到服務(wù)器返回的包,則判斷網(wǎng)絡(luò)斷開。

完整代碼,大家可以進(jìn)入源碼查看!

NetManager

NetManager 用于管理 NetNode,這是由于我們可能需要支持多個(gè)不同的連接對(duì)象,所以需要一個(gè) NetManager 專門來(lái)管理 NetNode,同時(shí),NetManager 作為一個(gè)單例,也可以方便我們調(diào)用網(wǎng)絡(luò)。

export class NetManager {
	private static _instance: NetManager = null;
	protected _channels: {
		[key: number]: NetNode
	} = {};
	public static getInstance(): NetManager {
		if (this._instance == null) {
			this._instance = new NetManager();
		}
		return this._instance;
	} // 添加Node,返回ChannelID    
	public setNetNode(newNode: NetNode, channelId: number = 0) {
		this._channels[channelId] = newNode;
	} // 移除Node    
	public removeNetNode(channelId: number) {
		delete this._channels[channelId];
	} // 調(diào)用Node連接    
	public connect(options: NetConnectOptions, channelId: number = 0): boolean {
		if (this._channels[channelId]) {
			return this._channels[channelId].connect(options);
		}
		return false;
	} // 調(diào)用Node發(fā)送   
	public send(buf: NetData, force: boolean = false, channelId: number = 0): boolean {
		let node = this._channels[channelId];
		if (node) {
			return node.send(buf, force);
		}
		return false;
	} // 發(fā)起請(qǐng)求,并在在結(jié)果返回時(shí)調(diào)用指定好的回調(diào)函數(shù)   
	public request(buf: NetData, rspCmd: number, rspObject: CallbackObject, showTips: boolean = true, force: boolean =
		false, channelId: number = 0) {
		let node = this._channels[channelId];
		if (node) {
			node.request(buf, rspCmd, rspObject, showTips, force);
		}
	} // 同request,但在request之前會(huì)先判斷隊(duì)列中是否已有rspCmd,如有重復(fù)的則直接返回    
	public requestUnique(buf: NetData, rspCmd: number, rspObject: CallbackObject, showTips: boolean = true, force:
		boolean = false, channelId: number = 0): boolean {
		let node = this._channels[channelId];
		if (node) {
			return node.requestUnique(buf, rspCmd, rspObject, showTips, force);
		}
		return false;
	} // 調(diào)用Node關(guān)閉  
	public close(code ? : number, reason ? : string, channelId: number = 0) {
		if (this._channels[channelId]) {
			return this._channels[channelId].closeSocket(code, reason);
		}
	}

測(cè)試?yán)?/strong>

接下來(lái)我們用一個(gè)簡(jiǎn)單的例子來(lái)演示一下網(wǎng)絡(luò)框架的基本使用,首先我們需要拼一個(gè)簡(jiǎn)單的界面用于展示,3個(gè)按鈕(連接、發(fā)送、關(guān)閉),2個(gè)輸入框(輸入 url、輸入要發(fā)送的內(nèi)容),一個(gè)文本框(顯示從服務(wù)器接收到的數(shù)據(jù)),如下圖所示。

該例子連接的是 websocket 官方的 echo.websocket.org 地址,這個(gè)服務(wù)器會(huì)將我們發(fā)送給它的所有消息都原樣返回給我們。

接下來(lái),實(shí)現(xiàn)一個(gè)簡(jiǎn)單的 Component,這里新建了一個(gè) NetExample.ts 文件,做的事情非常簡(jiǎn)單,在初始化的時(shí)候創(chuàng)建 NetNode、綁定默認(rèn)接收回調(diào),在接收回調(diào)中將服務(wù)器返回的文本顯示到 msgLabel中。接著是連接、發(fā)送和關(guān)閉幾個(gè)接口的實(shí)現(xiàn):

// 不關(guān)鍵的代碼省略
@ccclassexport
default class NetExample extends cc.Component {
	@property(cc.Label)
	textLabel: cc.Label = null;
	@property(cc.Label)
	urlLabel: cc.Label = null;
	@property(cc.RichText)
	msgLabel: cc.RichText = null;
	private lineCount: number = 0;
	onLoad() {
		let Node = new NetNode();
		Node.init(new WebSock(), new DefStringProtocol());
		Node.setResponeHandler(0, (cmd: number, data: NetData) => {
			if (this.lineCount > 5) {
				let idx = this.msgLabel.string.search("\n");
				this.msgLabel.string = this.msgLabel.string.substr(idx + 1);
			}
			this.msgLabel.string += `${data}\n`;
			++this.lineCount;
		});
		NetManager.getInstance().setNetNode(Node);
	}
	onConnectClick() {
		NetManager.getInstance().connect({
			url: this.urlLabel.string
		});
	}
	onSendClick() {
		NetManager.getInstance().send(this.textLabel.string);
	}
	onDisconnectClick() {
		NetManager.getInstance().close();
	}
}

代碼完成后,將其掛載到場(chǎng)景的 Canvas 節(jié)點(diǎn)下(其他節(jié)點(diǎn)也可以),然后將場(chǎng)景中的 Label 和 RichText 拖拽到我們的 NetExample 的屬性面板中:

運(yùn)行效果如下所示:

小結(jié)

可以看到,Websocket 的使用很簡(jiǎn)單,我們?cè)陂_發(fā)的過(guò)程中會(huì)碰到各種各樣的需求和問(wèn)題,要實(shí)現(xiàn)一個(gè)好的設(shè)計(jì),快速地解決問(wèn)題。

我們一方面需要對(duì)我們使用的技術(shù)本身有深入的理解,websocket 的底層協(xié)議傳輸是如何實(shí)現(xiàn)的?與 tcp、http 的區(qū)別在哪里?基于 websocket 能否使用 udp 進(jìn)行傳輸呢?使用 websocket 發(fā)送數(shù)據(jù)是否需要自己對(duì)數(shù)據(jù)流進(jìn)行分包(websocket 協(xié)議保證了包的完整)?數(shù)據(jù)的發(fā)送是否出現(xiàn)了發(fā)送緩存的堆積(查看 bufferedAmount)?

另外需要對(duì)我們的使用場(chǎng)景及需求本身的理解,對(duì)需求的理解越透徹,越能做出好的設(shè)計(jì)。哪些需求是項(xiàng)目相關(guān)的,哪些需求是通用的?通用的需求是必須的還是可選的?不同的變化我們應(yīng)該封裝成類或接口,使用多態(tài)的方式來(lái)實(shí)現(xiàn)呢?還是提供配置?回調(diào)綁定?事件通知?

我們需要設(shè)計(jì)出一個(gè)好的框架,來(lái)適用于下一個(gè)項(xiàng)目,并且在一個(gè)一個(gè)的項(xiàng)目中優(yōu)化迭代,這樣才能建立深厚的沉淀、提高效率。

以上就是CocosCreator通用框架設(shè)計(jì)之網(wǎng)絡(luò)的詳細(xì)內(nèi)容,更多關(guān)于CocosCreator框架設(shè)計(jì)之網(wǎng)絡(luò)的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

最新評(píng)論