Cocos2d-x3.2教程——【我所认识的Cocos2d-x】六、Cocos2d-x项目—网络管理器篇

真不好意思,原本星期一要发的网络管理器,由于昨天工作较忙,挪到今天来发了,万分抱歉。
上一节,我们了解UI管理器的详细用法,及一些基础的游戏框架搭建,那么我们基本业务类都已经有了,下面我们就开始添加网络管理,让我们的有游戏能联网,并封装管理器,以便使用。
本篇所用的Cocos2d-x版本为:
Cocos2d-x 3.2

编译器版本
VS2013

CocosStudio 1.5

本篇服务器以PHP为例

Cocos2d-x3.2教程——【我所认识的Cocos2d-x】
六、Cocos2d-x项目—网络管理器篇 具体的NetWork库,我希望大家能够自己详细的去了解其运作,讲的再细,说的再好,不如自己动手去了解其运作道理,这会使你的编程思维更具有开拓性。首先我们的项目已经添加了Network库了,那么下面在我们还需要添加对libcurl_imp.lib的支持,不然项目编译会
报错的。

右键项目,属性——配置属性——链接器——输入——附加依赖项中添加
libcurl_imp.lib
创建一个类,作为我们的网络管理器 类名就叫NetworkManager
然后引用头文件 添加命名空间 及常用函数

NetworkManager.h

//////////////////////////////////////////////////////////////////////////
#ifndef   _NET_WORK_MANAGER_H_
#define  _NET_WORK_MANAGER_H_
 
#include "cocos2d.h"
#include "extensions/cocos-ext.h"
#include "network/HttpClient.h"
#include "uimanager/UIManager.h"

//////////////////////////////////////////////////////////////////////////
USING_NS_CC;
USING_NS_CC_EXT;
using namespace std;
using namespace network;
 
#define        GET_G_NET()                                             (NetworkManager::getNewworkManager())
#define        GET_G_NET_LOGIC(x,y)                          (NetworkManager::getNewworkManager()->LoadUILogic(x,y))
#define        GET_G_NET_LISTENER(x,y)                   (NetworkManager::getNewworkManager()->setListenerAndCallfunND(x,y))
#define        GET_G_NET_SERVERADD(x)                (NetworkManager::getNewworkManager()->setServerAddress(x))
#define        GET_G_NET_REQUEST(x)                     (NetworkManager::getNewworkManager()->RequestUrlAddress(x))
#define        GET_G_NET_RR()                                    (NetworkManager::getNewworkManager()->httpRequestBusiness())
 
 
struct HttpState
{
       bool             m_bSucceed;             //是否成功;
       bool             m_bResolve;              //是否解析成功;
       string           m_vResData;             //返回数据;
 
};
 
enum MyChannel
{
       MC_0 = 0,                                 //默认渠道;
       MC_T,                                       //测试渠道;
       MC_G,                                      //正式渠道;
};
 
classNetworkManager :public BaseLayer
{
public:
       //构造函数;
       NetworkManager();
       //析构函数;
       ~NetworkManager();
       //静态创建网络管理器;
       static NetworkManager*getNewworkManager();
       //初始化数据;
       bool initNetworkData();
       //设置网址首地址;
       void setUrlFirst();
       //设置服务端地址;
       void setServerAddress(string addressStr);
       //设置回调类,及回调函数;
       void setListenerAndCallfunND(Ref*Listener, SEL_CallFuncND CallFuns);
       //请求业务;
       void httpRequestBusiness();
       //请求地址;
       void RequestUrlAddress(stringaddressStr);
       //支线程处理网络;
       static void threadingSupportNetwork(void*data);
       //网络回调;
       void onHttpRequestCompleted(HttpClient*sender, HttpResponse *response);
       //效验数据;
       void efficacyData(string sdata);
       //支线程结果监听;
       void threadOver(float dt);
protected:
       //渠道区分;
       int                                           __m_iChannel;
       //网址首连接;
       string                                     __m_sUrlFirst;
       //存储网址;
       string                                     __m_sStorageUrl;
       //监听者;       
       Ref*                                       __m_pListener;
       //回调地址;
       SEL_CallFuncND              __m_cCallfuncND;
       //支线程结束;
       bool                                      __m_bThread;
       //网络状态;
       HttpState                             __m_tHttpState;
};


```



NetworkManager.cpp

//////////////////////////////////////////////////////////////////////////
#include"NetworkManager.h"
 
 
static NetworkManager* myNewwork;
 
//测试地址;
#defineLOCATION_TEST "http://www.baidu.com"    
 
//构造函数;
NetworkManager::NetworkManager()
{
       //设置超时;
       HttpClient::getInstance()->setTimeoutForRead(20);
}
//析构函数;
NetworkManager::~NetworkManager()
{
       //退出时必须调用destroyInstance,否则程序崩溃;
       HttpClient::getInstance()->destroyInstance();
}
//静态创建网络管理器;
NetworkManager* NetworkManager::getNewworkManager()
{
       if (myNewwork == nullptr)
       {
              myNewwork = new NetworkManager();
              //初始化数据;
              myNewwork->initNetworkData();
       }
       return myNewwork;
}
//初始化数据;
bool NetworkManager::initNetworkData()
{
       __m_sUrlFirst = "";
       __m_iChannel = MC_T;
       __m_bThread = false;
       __m_tHttpState.m_bSucceed = false;
       __m_tHttpState.m_bResolve = false;
       __m_tHttpState.m_vResData = "";
       setUrlFirst();
 
       return true;
}
//设置网址首地址;
void NetworkManager::setUrlFirst()
{
       switch (__m_iChannel)
       {
       case MC_0:
              break;
       case MC_T:
              __m_sUrlFirst = LOCATION_TEST;
              break;
       case MC_G:
              break;
       default:
              break;
       }
}
//设置服务端地址;
void NetworkManager::setServerAddress(string addressStr)
{
       __m_sUrlFirst = addressStr;
}
//设置回调类,及回调函数;
voidNetworkManager::setListenerAndCallfunND(Ref* Listener, SEL_CallFuncND CallFuns)
{
       __m_pListener = Listener;
       __m_cCallfuncND = CallFuns;
}
 
//支线程处理网络;
void NetworkManager::threadingSupportNetwork(void* data)
{
       NetworkManager* p_This =(NetworkManager*)data;
       //创建HttpRequest对象,这里new出来用于保存数据;
       HttpRequest* request = new HttpRequest();
       //设置请求业务地址URL;
       request->setUrl(p_This->__m_sStorageUrl.c_str());
       //设置请求方式;
       request->setRequestType(HttpRequest::Type::GET);
       //设置回调对象及回调函数;
       request->setResponseCallback(CC_CALLBACK_2(NetworkManager::onHttpRequestCompleted,p_This));
       //设置标识;
       request->setTag("GETtest1");
       //使用CCHttpClient单例发送请求;
       HttpClient::getInstance()->send(request);
       //调用release;
       request->release();
}
//请求地址;
void NetworkManager::RequestUrlAddress(string addressStr)
{
       //重置监听;
       __m_tHttpState.m_bSucceed = false;
       __m_tHttpState.m_bResolve = false;
       __m_tHttpState.m_vResData = "";
       __m_bThread = false;
       GET_G_LOAD_S();
       //监听支线程是否结束;
       this->schedule(schedule_selector(NetworkManager::threadOver));
       //存储地址,当网络不好的情况下,用于重复申请;
       __m_sStorageUrl = __m_sUrlFirst +addressStr;
       //执行支线程;
       httpRequestBusiness();
}
//请求业务;
void NetworkManager::httpRequestBusiness()
{
       //支线程;
       thread t_Accep(threadingSupportNetwork,(void*)this);
       //线程分离;
       t_Accep.detach();
}
//网络回调;
void NetworkManager::onHttpRequestCompleted(HttpClient *sender, HttpResponse*response)
{
       if (!response)
       {
              return;
       }
       //网络状况;
       long statusCode =response->getResponseCode();
       log("response code: %ld",statusCode);
 
       //判断是否成功;
       if (!response->isSucceed())
       {//失败;
              log("response failed");
              //错误信息;
              log("error buffer: %s",response->getErrorBuffer());
              //返回逻辑1;
              ReturnLogic(1);
              return;
       }
 
       //连接服务端成功;
       __m_tHttpState.m_bSucceed = true;
       //获取请求数据;
       std::vector *buffer =response->getResponseData();
       std::string aastring;
       int ii = 0;
       int iii = buffer->size();
       for (; ii < iii; ii++) {
              aastring.push_back(buffer->at(ii));
       }
       //log("Data = %s",aastring.c_str());
       //请求引用计数不能为2;
       if(response->getHttpRequest()->getReferenceCount() != 2)
       {
              log("request ref count not 2,is %d", response->getHttpRequest()->getReferenceCount());
       }
       //效验数据;
       efficacyData(aastring);
}
//效验数据;
void NetworkManager::efficacyData(stringsdata)
{
       //根据与服务端的协议,自己根据实际情况进行效验;
       rapidjson::Document data_Json;
       data_Json.Parse<0>(sdata.c_str());
       if (data_Json.HasParseError())  
       {//解析错误;
              log("GetParseError%s\n", data_Json.GetParseError());
              //返回逻辑1;
              ReturnLogic(2);
              __m_tHttpState.m_bResolve = false;
              __m_tHttpState.m_vResData ="";
       }
       else
       {//解析正确;
              __m_tHttpState.m_bResolve = true;
              __m_tHttpState.m_vResData = sdata;
       }
       //线程结束;
       __m_bThread = true;
}
//支线程结果监听;
void NetworkManager::threadOver(float dt)
{
       if (__m_bThread)
       {//如果线程结束;
              //线程开关重置;
              __m_bThread = false;
              if (__m_tHttpState.m_bSucceed)
              {//如果连接服务器成功;
                     if(__m_tHttpState.m_bResolve)
                     {//如果数据解析正确;
                            if(__m_tHttpState.m_vResData.size() > 0)
                            {//如果数据不为0;
                                   if(__m_pListener && __m_cCallfuncND)
                                   {
                                          (__m_pListener->*__m_cCallfuncND)((Node*)this,&__m_tHttpState);
                                   }
                            }
                     }
              }
              //关闭计时器;
              this->unschedule(schedule_selector(NetworkManager::threadOver));
       }
}

```

 
创建好了,对于NetWork库的使用,大家可以去问度娘,上面有很详细的教程,我就不班门弄斧了,因为我觉得比人讲的比我能更深刻一些。(好自卑啊)
给大家推荐一篇文章,我觉得比较适合同学们做了解
http://blog.csdn.net/gf771115/article/details/24605155
然后将公用头文件将上对网络管理器的使用

#ifndef  __PUBLIC_HEADER_FILES_H__
#define __PUBLIC_HEADER_FILES_H__
 
#include"uimanager/UIManager.h"
#include"ResourcePath.h"
#include"json/rapidjson.h"
#include"json/document.h"
#include"NetworkManager.h"
 
enum Layer_Name
{
       LN_TEST_1 = 0,
       LN_TEST_2,
       LN_LOGO,
       LN_MENU,
       LN_CONFIG,
       LN_GAME,
       LN_TIPS,
};
 
#endif   //__PUBLIC_HEADER_FILES_H__

```


那么我就讲讲详细的网络管理器这块

//构造函数;
NetworkManager::NetworkManager()
{
       //设置超时;
       HttpClient::getInstance()->setTimeoutForRead(20);
}
//析构函数;
NetworkManager::~NetworkManager()
{
       //退出时必须调用destroyInstance,否则程序崩溃;
       HttpClient::getInstance()->destroyInstance();
}
//静态创建网络管理器;
NetworkManager* NetworkManager::getNewworkManager()
{
       if (myNewwork == nullptr)
       {
              myNewwork = new NetworkManager();
              //初始化数据;
              myNewwork->initNetworkData();
       }
       return myNewwork;
}

```


首先我单例了网络管理器,以便于使用,然后并宏定义,方便调用和预处理。然后在构造函数里对于超时时间做了下设置,一般游戏的超时连接都是20秒,但是为什么20秒,这个就需要自己思考了。
//设置网址首地址;
voidNetworkManager::setUrlFirst()
{
       switch (__m_iChannel)
       {
       case MC_0:
              break;
       case MC_T:
              __m_sUrlFirst = LOCATION_TEST;
              break;
       case MC_G:
              break;
       default:
              break;
       }
}

```


然后在析构的时候将资源是否掉。单例的时候做了一些数据的初始化,这个地方一般都是有测试服务器,外网测试服务器等,这里做了个渠道区分,也是为了以后分渠道准备的,因为以后分区后地址会很多。
//设置服务端地址;
void NetworkManager::setServerAddress(string addressStr)
{
       __m_sUrlFirst = addressStr;
}
//设置回调类,及回调函数;
void NetworkManager::setListenerAndCallfunND(Ref* Listener, SEL_CallFuncND CallFuns)
{
       __m_pListener = Listener;
       __m_cCallfuncND = CallFuns;
}
//请求地址;
void NetworkManager::RequestUrlAddress(string addressStr)
{
       //重置监听;
       __m_tHttpState.m_bSucceed = false;
       __m_tHttpState.m_bResolve = false;
       __m_tHttpState.m_vResData = "";
       __m_bThread = false;
       GET_G_LOAD_S();
       //监听支线程是否结束;
       this->schedule(schedule_selector(NetworkManager::threadOver));
       //存储地址,当网络不好的情况下,用于重复申请;
       __m_sStorageUrl = __m_sUrlFirst +addressStr;
       //执行支线程;
       httpRequestBusiness();
}
//请求业务;
void NetworkManager::httpRequestBusiness()
{
       //支线程;
       thread t_Accep(threadingSupportNetwork,(void*)this);
       //线程分离;
       t_Accep.detach();
}

```

然后将管理器的一般配置函数写好,基本上就完成了基础搭建。
然后将网络请求委托给支线程进行处理
//支线程处理网络;
voidNetworkManager::threadingSupportNetwork(void* data)
{
       NetworkManager* p_This =(NetworkManager*)data;
       //创建HttpRequest对象,这里new出来用于保存数据;
       HttpRequest* request = new HttpRequest();
       //设置请求业务地址URL;
       request->setUrl(p_This->__m_sStorageUrl.c_str());
       //设置请求方式;
       request->setRequestType(HttpRequest::Type::GET);
       //设置回调对象及回调函数;
       request->setResponseCallback(CC_CALLBACK_2(NetworkManager::onHttpRequestCompleted,p_This));
       //设置标识;
       request->setTag("GETtest1");
       //使用CCHttpClient单例发送请求;
       HttpClient::getInstance()->send(request);
       //调用release;
       request->release();
}
//网络回调;
voidNetworkManager::onHttpRequestCompleted(HttpClient *sender, HttpResponse*response)
{
       if (!response)
       {
              return;
       }
       //网络状况;
       long statusCode = response->getResponseCode();
       log("response code: %ld",statusCode);
 
       //判断是否成功;
       if (!response->isSucceed())
       {//失败;
              log("response failed");
              //错误信息;
              log("error buffer: %s",response->getErrorBuffer());
              //返回逻辑1;
              ReturnLogic(1);
              return;
       }
 
       //连接服务端成功;
       __m_tHttpState.m_bSucceed = true;
       //获取请求数据;
       std::vector *buffer =response->getResponseData();
       std::string aastring;
       int ii = 0;
       int iii = buffer->size();
       for (; ii < iii; ii++) {
              aastring.push_back(buffer->at(ii));
       }
       //log("Data = %s",aastring.c_str());
       //请求引用计数不能为2;
       if(response->getHttpRequest()->getReferenceCount() != 2)
       {
              log("request ref count not 2,is %d", response->getHttpRequest()->getReferenceCount());
       }
       //效验数据;
       efficacyData(aastring);
}

```

在response->getResponseCode()函数里会返回一些状态码,在网络回调中,我们必须要知道的一些网络基础知识,我想404大家都应该知道是什么吧?但是其他的呢?我将一些基本的状态码贴出来,以供大家参考。
 
这类状态代码表明服务器成功地接受了客户端请求。 
200 - 确定。客户端请求已成功。 
201 - 已创建。 
202 - 已接受。 
203 - 非权威性信息。 
204 - 无内容。 
205 - 重置内容。 
206 - 部分内容。 
207 - 多状态(WebDAV)。 
3xx - 重定向 
 
发生错误,客户端似乎有问题。例如,客户端请求不存在的页面,客户端未提供有效的身份验证信息。 
400 - 错误的请求。 
401 - 访问被拒绝。 
401.1 - 登录失败。 
401.2 - 服务器配置导致登录失败。 
401.3 - 由于 ACL 对资源的限制而未获得授权。 
401.4 - 筛选器授权失败。 
401.5 - ISAPI/CGI应用程序授权失败。 
401.7 – 由 Web 服务器上的 URL 验证策略拒绝访问。这个错误代码为 IIS 6.0 所专用。 
403 - 禁止访问:IIS 定义了几个不同的 403 错误,用于指示更为具体的错误原因: 
403.1 - 执行访问被禁止。 
403.2 - 读访问被禁止。 
403.3 - 写访问被禁止。 
403.4 - 要求 SSL。 
403.5 - 要求 SSL 128。 
403.6 - IP 地址被拒绝。 
403.7 - 要求客户端证书。 
403.8 - 站点访问被拒绝。 
403.9 - 用户数过多。 
403.10 - 配置无效。 
403.11 - 密码更改。 
403.12 - 拒绝访问映射表。 
403.13 - 客户端证书被吊销。 
403.14 - 拒绝目录列表。 
403.15 - 超出客户端访问许可。 
403.16 - 客户端证书不受信任或无效。 
403.17 - 客户端证书已过期或尚未生效。 
403.18 - 在当前的应用程序池中不能执行所请求的 URL。这个错误代码为 IIS 6.0 所专用。 
403.19 - 不能为这个应用程序池中的客户端执行 CGI。这个错误代码为 IIS 6.0 所专用。 
403.20 - Passport登录失败。这个错误代码为 IIS 6.0 所专用。 
404 - 未找到。 
404.0 -(无) – 没有找到文件或目录。 
404.1 - 无法通过请求的端口访问网站。 
404.2 - Web 服务扩展锁定策略阻止本请求。 
404.3 - MIME 映射策略阻止了此请求。
405 - 用来访问本页面的HTTP 谓词不被允许(方法不被允许) 
406 - 客户端浏览器不接受所请求页面的 MIME 类型。 
407 - 要求进行代理身份验证。
412 - 前提条件失败。 
413 – 请求实体太大。 
414 - 请求 URI 太长。 
415 – 不支持的媒体类型。
416 – 无法满足请求的范围。 
417 – 执行失败。 
423 – 锁定的错误。 
5xx - 服务器错误 
 
服务器由于遇到错误而不能完成该请求。 
500 - 内部服务器错误。 
500.12 - 应用程序正忙于在Web 服务器上重新启动。 
500.13 - Web 服务器太忙。 
500.15 - 不允许直接请求Global.asa。 
500.16 – UNC 授权凭据不正确。这个错误代码为 IIS 6.0 所专用。 
500.18 – 无法打开 URL 授权存储库。这个错误代码为 IIS 6.0 所专用。 
500.19 - 此文件的数据在元数据库中配置不正确。 
500.100 - 内部 ASP 错误。 
501 - 页眉值指定了未实现的配置。 
502 - Web 服务器用作网关或代理服务器时收到了无效响应。 
502.1 - CGI 应用程序超时。 
502.2 - CGI 应用程序出错。 
503 - 服务不可用。这个错误代码为 IIS 6.0 所专用。 
504 - 网关超时。 
505 - HTTP 版本不受支持。
其实一般我们只需要判断200就好了,其他原因我们可以自己写个网络判断模块进行处理就好了
当我们接收到数据后,这里面还有个重要的步骤,就是数据效验!
客户端一定要对数据进行有效的效验,才能保证数据的完整性与安全性。一般数据效验可以跟服务端按照规定的协议进行效验,在代码里我就不过多的去描述了。
然后我们基本的网络管理器就搭建成功了!!

现在还需要什么?是的,提示层!如果我们网络管理器对网络处理及数据解析发生了错误怎么办?肯定不能卡住啊,所以一般情况下,我们会重新请求或执行其他步骤!
 那么我们开始创建提示层UI_Tpis类,同样在CocosStudio里也创建一份
#ifndef  _UI_TIPS_H_
#define  _UI_TIPS_H_
 
#include"PublicHeaderFiles.h"
 
class UI_Tips:public BaseLayer
{
public:
       //重载创建;
       static UI_Tips * create(const int type);
       //初始化;
       virtual bool init();
       //创建;
       CREATE_FUNC(UI_Tips);
       //重载;
       virtual void showUI();
       //显示;
       void showTipsUI();
       //菜单事件;
       void Menu_Event(Ref *pSender,Widget::TouchEventType type);
       //读取数据;
       void readData(const int type);
public:
       //studio;
       Layer*                         m_pUiLayer;
       //布局文件;
       Layout*                      m_pWidget;
       //类型;
       int                               m_iTallType;
};
 
#endif //_UI_TIPS_H_

```

.cpp
#include"UI_Tips.h"
 
//重载创建;
UI_Tips *UI_Tips::create(const int type)
{
       UI_Tips *ret = new UI_Tips();
       if (ret && ret->init())
       {
              ret->autorelease();
              ret->readData(type);
              return ret;
       }
       else
       {
              CC_SAFE_DELETE(ret);
              return nullptr;
       }
}
//初始化;
bool UI_Tips::init()
{
       if (!Layer::init())
       {
              return false;
       }
 
       m_pUiLayer = nullptr;
       m_pWidget = nullptr;
       //继承BaseLayer,负责动画索引类型;
       m_iActionIndex = GAI_NULL;
 
       return true;
}
//读取数据;
void UI_Tips::readData(const int type)
{
       m_iTallType = type;
}
//重载;
void UI_Tips::showUI()
{
       showTipsUI();
}
//显示;
void UI_Tips::showTipsUI()
{
       if (m_pUiLayer == nullptr)
       {
              m_pUiLayer = Layer::create();
              this->addChild(m_pUiLayer, 3,0);
 
              auto maskLayer =LayerColor::create(Color4B(0, 0, 0, 160));
              this->addChild(maskLayer, 0);
       }
 
       m_pWidget =static_cast(GUIReader::getInstance()->widgetFromJsonFile(RES_UI_TIPS));
       m_pUiLayer->addChild(m_pWidget);
 
       auto m_pConfig =static_cast(Helper::seekWidgetByName(m_pWidget,"Button_Enter"));
       m_pConfig->addTouchEventListener(CC_CALLBACK_2(UI_Tips::Menu_Event,this));
 
       auto m_pImgBG =static_cast(Helper::seekWidgetByName(m_pWidget,"Image_BG")); 
 
       string tallStr = "";
       switch (m_iTallType)
       {
       case 0:
              break;
       case 1:
              break;
       case 2:
              tallStr = "GetParseErrorExpect either an object or array at root";
              break;
       default:
              break;
       }
 
 
       auto _label = Label::create();
       _label->setDimensions(210, 160);
       _label->setAlignment(TextHAlignment::CENTER,TextVAlignment::CENTER);
       _label->setSystemFontSize(32);
       _label->setString(tallStr.c_str());
       _label->setPosition(Vec2(m_pImgBG->getContentSize().width/ 2+100, m_pImgBG->getContentSize().height / 2-10));
       _label->setColor(ccBLACK);
       m_pImgBG->addChild(_label);
 
}
//菜单事件;
void UI_Tips::Menu_Event(Ref *pSender, Widget::TouchEventType type)
{
       switch (type)
       {
              //触摸事件;
       case Widget::TouchEventType::BEGAN:
              break;
              //移动事件;
       case Widget::TouchEventType::MOVED:
              break;
              //抬起事件;
       case Widget::TouchEventType::ENDED:
              //重新请求业务;
              GET_G_NET_RR();
              this->runAction(Sequence::create(
                     DelayTime::create(0.2f),
                     RemoveSelf::create(true),
                     nullptr));
 
              break;
              //越界事件;
       case Widget::TouchEventType::CANCELED:
              break;
       default:
              break;
       }
 
}

```

 
接下来我们需要修改下管理器GameMain的函数就好了
将UI管理器与网络管理器代码封装下
//设置UI管理器;
void GameMain::setUIManager()
{
       //设置UI管理器与管理器连接;
       GET_T_SM(this);
       //逻辑回调地址;
       SEL_CallFuncND t_Logic =callfuncND_selector(GameMain::setUILayerLogic);
       //绘制回调地址;
       SEL_CallFuncND t_Drwa = callfuncND_selector(GameMain::setUILayerDraw);
       //设置UI管理器与管理器逻辑连接;
       GET_G_LOGIC(t_Logic, t_Drwa);
       //加载UI管理器;
       this->addChild(GET_G_UI(), 0);
       //创建Loading层;
       UI_Loading* loadingLayer =UI_Loading::create();
       //设置Loading层;
       GET_G_UI()->setLoadIngLayer(loadingLayer);
       loadingLayer->showUI();
       //设置业务 执行逻辑——LN_LOGO;
       setUILayerLogic(nullptr, (void*)LN_LOGO);
}
//设置网络管理器;
void GameMain::setNetworkManager()
{
       //管理器加载;
       this->addChild(GET_G_NET(), -1);
       //设置错误返回地址;
       GET_G_NET_LOGIC(this,callfuncND_selector(GameMain::setNetWorkLogic));
       //设置回调类,及回调函数;
       //哪个类要执行业务,就将这个函数写到哪个类里;
       //由于是测试,我将回调写在了管理器里;
       GET_G_NET_LISTENER(this,callfuncND_selector(GameMain::setNetWorkLogicRes));
       //请求业务;
       //GET_G_NET_REQUEST("");
}

```

然后给网络管理器 2个回调地址 
网络回调 一般情况都是错误提示,可以在里面写提示框
业务回调 是我们具体哪个类 执行了网络业务 然后对调给哪个类
//网络回调;
void GameMain::setNetWorkLogic(Node* pSender, void* cIndex)
{
       //关闭Loading;
       GET_G_LOAD_E();
       //返回错误类型;
       int m_iIndex = (int)cIndex;
       //根据返回错误信息类型,进行创建;
       UI_Tips* m_pTips =UI_Tips::create(m_iIndex);
       this->addChild(m_pTips, 1);
       m_pTips->showUI();
}
//业务回调;
void GameMain::setNetWorkLogicRes(Node* pSender, void* cIndex)
{
       HttpState* temp = (HttpState*)(cIndex);
       log("%s",temp->m_vResData.c_str());
}

```

然后将业务申请写到Menu类的Button对调函数里
//菜单事件;
void UI_Menu::Menu_Event(Ref *pSender, Widget::TouchEventType type)
{
       switch (type)
       {
       case Widget::TouchEventType::BEGAN:
              break;
       case Widget::TouchEventType::MOVED:
              break;
       case Widget::TouchEventType::ENDED:
              {
                     int tag =((Button*)pSender)->getTag();
                     switch (tag)
                     {
                     case 10:
                            log("Config");
                            {
                                   //由于Config类是属于Menu下的,所以我将Config加载在Menu上;
                                   UI_Config*temp = UI_Config::create();
                                   this->addChild(temp,4);
                                   //这里是为了测试返回逻辑的函数;
                                   temp->LoadUILogic(this,callfuncND_selector(UI_Menu::TestRes));
                                   temp->showUI();
                            }
                            break;
                     default:
                            log("Button =%d", tag);
                            //请求业务;
                            GET_G_NET_REQUEST("");
                            break;
                     }
              }
              break;
       case Widget::TouchEventType::CANCELED:
              break;
       default:
              break;
       }
}

```

OK,那么我们运行看下!
   
为什么会报错误呢?这是因为,我写的请求地址是百度,由于百度给反馈的数据,并不是一个有效的Json数据,所以在数据解析的时候出错了,我们看下代码。
//效验数据;
void NetworkManager::efficacyData(string sdata)
{
       //根据与服务端的协议,自己根据实际情况进行效验;
       rapidjson::Document data_Json;
       data_Json.Parse<0>(sdata.c_str());
       if (data_Json.HasParseError())  
       {//解析错误;
              log("GetParseError%s\n", data_Json.GetParseError());
              //返回逻辑1;
              ReturnLogic(2);
              __m_tHttpState.m_bResolve = false;
              __m_tHttpState.m_vResData ="";
       }
       else
       {//解析正确;
              __m_tHttpState.m_bResolve = true;
              __m_tHttpState.m_vResData = sdata;
       }
       //线程结束;
       __m_bThread = true;
}

```

在数据解析错误的时候 我返回了逻辑2,那么我们看下提示层函数
string tallStr ="";
       switch (m_iTallType)
       {
       case 0:
              break;
       case 1:
              break;
       case 2:
              tallStr = "GetParseErrorExpect either an object or array at root";
              break;
       default:
              break;
       }

```

OK!网络这块真的很大,也是非常重要的位置,下一章我们将会针对数据类,进行一节大概的了解,我尽可能将,数据管理器及数据库管理器一起讲解下。
那么,我们下一节再见!

赞!mark!

:7: 讲的有点粗了,不够详细

看到这篇教程我想说一些教程无关的东西,就当抛砖引玉吧。
楼主的NetworkManager.h头文件里引用了大量头文件,比如cocos2d,ui,cocostudio相关头文件,这些其实是没有必要的,既然是NetWork管理,那功能就应该很明确,只负责网络相关,引这么多ui相关的头文件是没有意义的。另外NetworkManager.h文件里使用了大量using namespace,这样会造成命名空间的污染,google一下头文件命名空间污染会找到很多相关的文章。

之所以在这里提这些是因为我认为别人在学习楼主的教程时可能会收到其代码风格的影响,因为大部分来学习的人肯定编码能力是不如楼主的,那么作为教程的编写者在代码风格方面注意的细节就更多了。我以前写代码也会有我提到过的这些问题,也是别的高人告诉我后才会对其更加注意。我也从楼主的教程中学到很多东西,但看到问题还是要提出来,这样大家才能一起进步。

谢谢你的提醒,我是复制粘贴习惯了,留下来的坏毛病,感谢你的提醒及提示~:7:

:8: 发现源码里有点问题…

:9:楼主 有 发到博客 上吗= =。。。这论坛的代码 高亮 太蛋疼了。。。根本 就没亮。。。:5:

本来打算弄个博客的 但是没时间 我手动改了 代码高亮 你看看

干货不解释。

是不是太干了…怕别人看不懂… :10: