標籤:style class blog code java http
介紹
WebSocket是HTML5開始提供的一種瀏覽器與伺服器間進行全雙工系統通訊的網路技術。在WebSocket API中,瀏覽器和伺服器只需要做一個握手的動作,然後,瀏覽器和伺服器之間就形成了一條快速通道。兩者之間就直接可以資料互相傳送。
Cocos2d-x引擎整合libwebsockets,並在libwebsockets的用戶端API基礎上封裝了一層易用的介面,使得引擎在C++, JS, Lua層都能方便的使用WebSocket來進行遊戲網路通訊。
引擎支援最新的WebSocket Version 13。
在C++中使用
詳細代碼可參考引擎目錄下的/samples/Cpp/TestCpp/Classes/ExtensionsTest/NetworkTest/WebSocketTest.cpp檔案。
標頭檔中的準備工作
首先需要include WebSocket的標頭檔。
#include "network/WebSocket.h"
cocos2d::network::WebSocket::Delegate定義了使用WebScocket需要監聽的回調通知介面。使用WebSocket的類,需要public繼承這個Delegate。
class WebSocketTestLayer : public cocos2d::Layer, public cocos2d::network::WebSocket::Delegate
並Override下面的4個介面:
virtual void onOpen(cocos2d::network::WebSocket* ws);virtual void onMessage(cocos2d::network::WebSocket* ws, const cocos2d::network::WebSocket::Data& data);virtual void onClose(cocos2d::network::WebSocket* ws);virtual void onError(cocos2d::network::WebSocket* ws, const cocos2d::network::WebSocket::ErrorCode& error);
後面我們再詳細介紹每個回調介面的含義。
建立WebSocket並初始化
WebSocket.org 提供了一個專門用來測試WebSocket的伺服器"ws://echo.websocket.org"。 測試代碼以連結這個伺服器為例,展示如何在Cocos2d-x中使用WebSocket。
建立一個WebSocket:
cocos2d::network::WebSocket* _wsiSendText = new network::WebSocket();
init第一個參數是delegate,設定為this,第二個參數是伺服器位址。 URL中的"ws://"標識是WebSocket協議,加密的WebSocket為"wss://".
_wsiSendText->init(*this, "ws://echo.websocket.org")
WebSocket訊息監聽
在調用send發送訊息之前,先來看下4個訊息回調。
onOpen
init會觸發WebSocket連結的伺服器,如果成功,WebSocket就會調用onOpen,告訴調用者,用戶端到伺服器的通訊鏈路已經成功建立,可以收發訊息了。
void WebSocketTestLayer::onOpen(network::WebSocket* ws){ if (ws == _wsiSendText) { _sendTextStatus->setString("Send Text WS was opened."); }}
onMessage
network::WebSocket::DataObject Storage Service用戶端接收到的資料, isBinary屬性用來判斷資料是二進位還是文本,len說明資料長度,bytes指向資料。
void WebSocketTestLayer::onMessage(network::WebSocket* ws, const network::WebSocket::Data& data){ if (!data.isBinary) { _sendTextTimes++; char times[100] = {0}; sprintf(times, "%d", _sendTextTimes); std::string textStr = std::string("response text msg: ")+data.bytes+", "+times; log("%s", textStr.c_str()); _sendTextStatus->setString(textStr.c_str()); }}
onClose
不管是伺服器主動還是被動關閉了WebSocket,用戶端將收到這個請求後,需要釋放WebSocket記憶體,並養成良好的習慣:置null 指標。
void WebSocketTestLayer::onClose(network::WebSocket* ws){ if (ws == _wsiSendText) { _wsiSendText = NULL; } CC_SAFE_DELETE(ws);}
onError
用戶端發送的請求,如果發生錯誤,就會收到onError訊息,遊戲針對不同的錯誤碼,做出相應的處理。
void WebSocketTestLayer::onError(network::WebSocket* ws, const network::WebSocket::ErrorCode& error){ log("Error was fired, error code: %d", error); if (ws == _wsiSendText) { char buf[100] = {0}; sprintf(buf, "an error was fired, code: %d", error); _sendTextStatus->setString(buf); }}
send訊息到伺服器
在init之後,我們就可以調用send介面,往伺服器發送資料請求。send有文本和二進位兩中模式。
發送文本
_wsiSendText->send("Hello WebSocket, I‘m a text message.");
發送位元據(多了一個len參數)
_wsiSendBinary->send((unsigned char*)buf, sizeof(buf));
主動關閉WebSocket
這是讓整個流程變得完整的關鍵步驟, 當某個WebSocket的通訊不再使用的時候,我們必須手動關閉這個WebSocket與伺服器的串連。close會觸發onClose訊息,而後onClose裡面,我們釋放記憶體。
_wsiSendText->close();
在Lua中使用
詳細代碼可參考引擎目錄下的/samples/Lua/TestLua/Resources/luaScript/ExtensionTest/WebProxyTest.lua檔案。
建立WebSocket對象
指令碼介面相對C++要簡單很多,沒有標頭檔,建立WebSocket對象使用下面的一行代碼搞定。 參數是伺服器位址。
wsSendText = WebSocket:create("ws://echo.websocket.org")
定義並註冊訊息回呼函數
回呼函數是普通的Lua function,4個訊息回調和c++的用途一致,參考上面的說明。
local function wsSendTextOpen(strData) sendTextStatus:setString("Send Text WS was opened.")endlocal function wsSendTextMessage(strData) receiveTextTimes= receiveTextTimes + 1 local strInfo= "response text msg: "..strData..", "..receiveTextTimes sendTextStatus:setString(strInfo)endlocal function wsSendTextClose(strData) print("_wsiSendText websocket instance closed.") sendTextStatus = nil wsSendText = nilendlocal function wsSendTextError(strData) print("sendText Error was fired")end
Lua的訊息註冊不同於C++的繼承 & Override,有單獨的介面registerScriptHandler。 registerScriptHandler第一個參數是回呼函數名,第二個參數是回調類型。 每一個WebSocket執行個體都需要綁定一次。
if nil ~= wsSendText then wsSendText:registerScriptHandler(wsSendTextOpen,cc.WEBSOCKET_OPEN) wsSendText:registerScriptHandler(wsSendTextMessage,cc.WEBSOCKET_MESSAGE) wsSendText:registerScriptHandler(wsSendTextClose,cc.WEBSOCKET_CLOSE) wsSendText:registerScriptHandler(wsSendTextError,cc.WEBSOCKET_ERROR)end
send訊息
Lua中發送不區分文本或二進位模式,均使用下面的介面。
wsSendText:sendString("Hello WebSocket中文, I‘m a text message.")
主動關閉WebSocket
當某個WebSocket的通訊不再使用的時候,我們必須手動關閉這個WebSocket與伺服器的串連,以釋放伺服器和用戶端的資源。close會觸發cc.WEBSOCKET_CLOSE訊息。
wsSendText:close()