【Cocos2dx-3.x】通信协议之WebSocket通信协议篇

来源:互联网 发布:百度云不限速版本mac 编辑:程序博客网 时间:2024/05/16 07:10

 好记性不如烂笔头

前言

WebSockets协议的优势在于:
1. Header : 互相沟通的Header是很小的-大概只有 2 Bytes
2. Server Push : 服务器可以主动传送数据给客户端,全双工通信
具体介绍可以查阅有关书籍看看,这里,这里,还有这里。下面是在Cocos2dx中使用的WebSocket网络协议的一个小例子,在TestCpp中可以找到源码;

预备工作

首先创建4个按钮,作用分别是:打开WebSocket链接、发送字符串消息、发送二进制消息、关闭WebSocket链接;(创建按钮方法这里省略)
如图所示:775A88A1-8F5D-47D0-BDAD-4D6A5B94B31F

WebSocket协议

 1.使用WeSocket协议
首先要把相关头文件包含进来:

#include "network/WebSocket.h"using namespace cocos2d::network;

其次要继承WebSocket::Delegate,并且还要实现Delegate的4个虚函数:
我们可以去 Delegate源码中看有哪几个需要我们实现的,如图:

// 当打开WebSocket连接时会被调用virtualvoidonOpen(WebSocket*ws);// 当返回数据时会被调用virtualvoidonMessage(WebSocket*ws,constWebSocket::Data&data);// 当关闭WebSocket连接时会被调用virtualvoidonClose(WebSocket*ws);// 当连接出现错误时会被调用virtualvoidonError(WebSocket*ws,constWebSocket::ErrorCode&error);

99309CCE-251E-4BFE-8915-44C1AD6A258A当我们点击1.Open WebSocket按钮时,我们创建new3个WebSocket对象,并调用init方法来初始化它,init方法:

@param &delegate 第一个参数指的是接收WebSocket数据的代理类,

@param &url 第二个参数指的是服务器地址;

CE66905A-9471-4407-AA8E-2122A52A8981点击此时onOpen(WebSocket* ws)函数会做出响应:

//当打开WebSocket连接时会调用这个函数void TestWebSocket::onOpen(WebSocket* ws){//输出链接打开消息log("Websocket (%p) opened", ws);if (ws == _wsiSendText){MessageBox("Send Text WS was opened.\nws://echo.websocket.org", "提示");}else if (ws == _wsiSendBinary){MessageBox("Send Binary WS was opened.\nws://echo.websocket.org.", "提示");}else if (ws == _wsiError){MessageBox("error test will never go here.\nws://invalid.url.com", "提示");CCASSERT(0, "error test will never go here.");}}


按钮1 Open WebSocket 所响应的事件完整代码段:

// 创建3个WebSocket对象_wsiSendText = newWebSocket();_wsiSendBinary = newWebSocket();_wsiError = newWebSocket();// *this 接收webSocket数据的代理类(本类),"ws://echo.websocket.org"服务器地址_wsiSendText->init(*this,"ws://echo.websocket.org");_wsiSendBinary->init(*this,"ws://echo.websocket.org");// 测试Error,这个服务器地址错_wsiError->init(*this,"ws://invalid.url.com");

当我们点击2 Send Text按钮,利用send()函数发送字符串消息:
首先判断,链接是否成功,利用getReadyState()函数来获得链接状态,与WebSocket中提供的枚举值进行判断,其中枚举值包括OPEN,CONNECTING,CLOSING,CLOSED;
如图:
E006B20C-C332-447D-A275-94FAA658AA5A
按钮2 Send Text所响应的事件完整代码段:

if (! _wsiSendText){<span style="white-space:pre"></span>return;}//利用getReadyState()函数来获取链接状态,进行对比;这里额OPEN,是枚举值;其他分别是 CONNECTING,CLOSING,CLOSED等if (_wsiSendText->getReadyState() == network::WebSocket::State::OPEN){CCLOG("已经打开成功,正发送字符串消息");//向服务器发送字符串消息_wsiSendText->send("Hello WebSocket, I'm a text message.");}else{std::string warningStr = "send text websocket instance wasn't ready...";log("%s", warningStr.c_str());}

此时onMessage(WebSocket* ws, const WebSocket::Data& data)会做出响应,这里后面会说到。
当我们点击3 Send Binary按钮,利用send()函数发送二进制消息,按钮2 Send Text和按钮3 Send Binary区别在于发送消息方式,一个是字符串,一个是二进制:
按钮3 Send Binary所响应的事件完整代码段:

if(!_wsiSendBinary){<span style="white-space:pre"></span>return;}// 利用getReadyState()函数来获取链接状态,进行对比;这里额OPEN,是枚举值;其他分别是 CONNECTING,CLOSING,CLOSED等if(_wsiSendBinary->getReadyState()==network::WebSocket::State::OPEN){<span style="white-space:pre"></span>CCLOG("已经打开成功,正发送字符串消息");<span style="white-space:pre"></span>// 向服务器发送二进制消息<span style="white-space:pre"></span>charbuf[]="Hello WebSocket,\0 I'm\0 a\0 binary\0 message\0.";<span style="white-space:pre"></span>_wsiSendBinary->send((unsignedchar*)buf,sizeof(buf));}else{<span style="white-space:pre"></span>std::stringwarningStr="send binary websocket instance wasn't ready...";<span style="white-space:pre"></span>log("%s",warningStr.c_str());}

此时onMessage(WebSocket* ws, const WebSocket::Data& data)会做出响应,这里先说onMessage(WebSocket* ws, const WebSocket::Data& data)这个函数,它返回数据,(依据项目所需进行响应处理)这里我们只做了输出处理.输出前我们先判断是不是二进制,分别用2种方式输出数据:

//输出返回的数据void TestWebSocket::onMessage(WebSocket* ws, const WebSocket::Data& data){//判断是不是数据是否是2进制,利用不同方法输出数据        //      当我们点击2 Send Text按钮!data.isBinary成立,会走非二进制输出,因为按钮2 Send Test发送的是字符串消息if (!data.isBinary){//非二进制输出_sendTextTimes++;char times[100] = {0};sprintf(times, "%d", _sendTextTimes);std::string textStr = std::string("response text msg: ")+data.bytes+", "+times;CCLOG("%s", textStr.c_str());std::string textStr1 = std::string("文本输出:\nresponse text msg: ")+data.bytes+", "+times;MessageBox(textStr1.c_str(), "提示");}         //      当我们点击3.Send Binary按钮时,会走二进制输出,因为按钮3. Send Binary发送的是二进制消息else{//二进制输出_sendBinaryTimes++;char times[100] = {0};sprintf(times, "%d", _sendBinaryTimes);std::string binaryStr = "response bin msg: ";for (int i = 0; i < data.len; ++i){if (data.bytes[i] != '\0'){binaryStr += data.bytes[i];}else{binaryStr += "\'\\0\'";}}binaryStr += std::string(", ")+times;CCLOG("%s", binaryStr.c_str());std::string textStr = std::string("二进制类型输出:\n")+binaryStr.c_str();MessageBox(textStr.c_str(), "提示");}}

 当我们点击4 Close WebSocket按钮,利用利用close()函数来关闭WebSocket连接:

if(_wsiSendText){<span style="white-space:pre"></span>// 调用关闭<span style="white-space:pre"></span>_wsiSendText->close();}if(_wsiSendBinary){<span style="white-space:pre"></span>_wsiSendBinary->close();}if(_wsiError){<span style="white-space:pre"></span>_wsiError->close();}

此时会调用onClose(WebSocket* ws)函数,onClose中做了写清空处理:

//关闭WebSocket连接void TestWebSocket::onClose(WebSocket* ws){log("websocket instance (%p) closed.", ws);if (ws == _wsiSendText){_wsiSendText = nullptr;}else if (ws == _wsiSendBinary){_wsiSendBinary = nullptr;}else if (ws == _wsiError){_wsiError = nullptr;}//删除操作CC_SAFE_DELETE(ws);}

最后是错误信息函数onError(WebSocket* ws, constWebSocket::ErrorCode& error),这个函数会监听每一步操作,例如,之前出事话时,赋连接错误,这里就会提出:

// 错误信息voidTestWebSocket::onError(WebSocket*ws,constWebSocket::ErrorCode&error){<span style="white-space:pre"></span>charbuf[100]={0};<span style="white-space:pre"></span>sprintf(buf,"an error was fired, code:\n %d    ,%p",error,ws);<span style="white-space:pre"></span>MessageBox(buf,"提示");<span style="white-space:pre"></span>CCLOG("Error was fired, error code: %d",error);}

运行效果展示图

当点击1 Open WebSocket按钮

xg2xg1xg3_3C85D8499-8E69-47CA-971E-4B5174D834DF

当点击2 Send Text按钮

sendtext2sendtest1

 
当点击3 Send Binary按钮

b33

sendtest1

当点击4 Close WebSocket按钮

24F9F8BD-CBE1-4A6D-BC87-B564AFBB7479

到这里就结束了,想看运行结果的,可以再我得getHub上下载源码,在控制台可以看到详细的输出与调用流程,点击这里下载本节源码;

总结

网络篇到此就算结束了,后期会根据工作上的学习,来完善这3章节的网络知识,本章节代码在TestCpp中均可找到。
更多文章可以访问我得个人博客:www.sydev.cn

0 0
原创粉丝点击