cocos2dx获取网络时间(二):浅析CCHttpClient

  在上一篇文章cocos2dx获取网络时间(一)中,我们使用CCHttpClient进行网络时间的数据请求和使用rapidjson解析Http请求得到的json数据 。在文章的最后 ,我留下了一个问题,怎么封装一个类来实现我们的方法。

  新建一个c++类 ,命名为NetTime,继承自CCNode并重写init()方法。然后引入CCHttpClient和rapidjson需要的头文件。我们的需求是可以返回NetTime的年,月,日,小时,分和秒,分别定义它们的private字段和public方法:

 1 #ifndef __NETTIME_H__
 2 #define __NETTIME_H__
 3 #include "cocos2d.h"
 4 #include "cocos-ext.h"
 5 #include "CocoStudio\Json\rapidjson\rapidjson.h"
 6 using namespace cocos2d;
 7 using namespace extension;
 8 using namespace rapidjson;
 9
10 class NetTime:public CCNode
11 {
12 public:
13     CREATE_FUNC(NetTime);
14     int getYear(){
15         return _year;
16     };
17     int getMonth(){
18         return _month;
19     };
20     int getDay(){
21         return _day;
22     };
23     int getHour(){
24         return _hour;
25     };
26     int getMinute(){
27         return _minute;
28     };
29     int getSecond(){
30         return _second;
31     };
32     void getNetTime();
33     void requestNetTime();
34 private:
35     virtual bool init();
36     int _year, _month, _day, _hour, _minute, _second;
37     void onHttpComplete(CCHttpClient * sender, CCHttpResponse * response);
38     void readJson(std::string jsonStr);
39 };
40 #endif

  我们还需要一个requestNetTime方法来发起http请求,并在回调方法里面实现数据的获取和解析,直接把前面的代码拷贝过来即可:

 1 #include "NetTime.h"
 2
 3 bool NetTime::init()
 4 {
 5     bool bRet = false;
 6     do
 7     {
 8         CC_BREAK_IF(!CCNode::init());
 9
10         bRet = true;
11     } while (0);
12     return bRet;
13 }
14
15 void NetTime::requestNetTime()
16 {
17     CCHttpRequest * request = new CCHttpRequest();
18     request->setUrl("http://115.159.3.250:1227/WebTime.svc/");
19     request->setRequestType(CCHttpRequest::kHttpGet);
20     request->setTag("WebTime");
21     request->setResponseCallback(this, httpresponse_selector(NetTime::onHttpComplete));
22     CCHttpClient::getInstance()->send(request);
23 }
24
25 void NetTime::onHttpComplete(CCHttpClient * sender, CCHttpResponse * response)
26 {
27     CCHttpClient::getInstance()->release();
28     if (!response)
29         return;
30     if (0 != strlen(response->getHttpRequest()->getTag()))
31     {
32         CCLog("%s completed", response->getHttpRequest()->getTag());
33     }
34     int statusCode = response->getResponseCode();
35     char statusString[64] = {};
36     sprintf(statusString, "HTTP Status: %d, tag = %s", statusCode, response->getHttpRequest()->getTag());
37     CCLog("%s", statusString);
38     if (!response->isSucceed())
39     {
40         CCLog("response failed");
41         CCLog("error buffer:%s", response->getErrorBuffer());
42         return;
43     }
44     std::vector<char> * buffer = response->getResponseData();
45     std::string str;
46     for (unsigned i = 0; i < buffer->size(); i++)
47     {
48         char a = (*buffer)[i];
49         str.append(1, a);
50     }
51     CCLog("%s", str.c_str());
52     readJson(str);
53 }
54
55 void NetTime::readJson(std::string jsonStr)
56 {
57     Document doc;
58     doc.Parse<0>(jsonStr.c_str());
59     if (!doc.IsObject())
60         return;
61     if (doc.HasMember("Year") && doc.HasMember("Month") && doc.HasMember("Day") && doc.HasMember("Hour") && doc.HasMember("Minute") && doc.HasMember("Second"))
62     {
63         _year = doc["Year"].GetInt();
64         _month = doc["Month"].GetInt();
65         _day = doc["Day"].GetInt();
66         _hour = doc["Hour"].GetInt();
67         _minute = doc["Minute"].GetInt();
68         _second = doc["Second"].GetInt();
69     }
70 }

  看到这里 ,读者可能会忍不住要说了,Leandro真是一个大忽悠,如此简单的类封装都要单独拿出来写一篇!

  各位客官莫着急,请接着向下看:

  我们回到HelloWorldScene.cpp的init方法,注释掉前面发起网络请求的代码,接着使用我们的NetTime类:

  

 1     /*    CCHttpRequest * request = new CCHttpRequest();
 2         request->setUrl("http://localhost:23244/NetTime.svc/Time");
 3         request->setRequestType(CCHttpRequest::kHttpGet);
 4         request->setTag("WebTime");
 5         request->setResponseCallback(this, httpresponse_selector(HelloWorld::onHttpComplete));
 6         CCHttpClient::getInstance()->send(request);*/
 7
 8         NetTime * netTime = NetTime::create();
 9         netTime->requestNetTime();
10         char timeStr[50];
11         sprintf(timeStr, "NetTime  %d-%d-%d %d:%d:%d",
12             netTime->getYear(), netTime->getMonth(), netTime->getDay(),
13             netTime->getHour(), netTime->getMinute(), netTime->getSecond());
14         CCLabelTTF *timeLabel = CCLabelTTF::create(timeStr, "Arial", 18);
15         timeLabel->setPosition(ccp(240, 50));
16         this->addChild(timeLabel);

  进行调试:

  

  异常信息为:变量timeStr内存损坏。可以分析得到引发此异常最可能的原因是netTime的getYear(),getMonth()...方法均没有返回正确的值。

  再来看上面NetTime类的代码,发现对_year,_month,_day,_hour,_minute,_second的赋值操作均在onHttpComplete()方法,也就是CCHttpClient网络请求的回调方法中。

  由此可以断定,在我们使用netTime的getYear(),getMonth()...方法返回字段值的时候 ,onHttpComplete()回调方法并没有执行。那么,为什么回调方法没有执行呢??

  通过查看Cocos2dx的api文档,发现对CCHttpClient有这样一句描述:处理异步http请求的单例模式 一旦请求完成,一个在生成请求时被提供的回调函数,会被发到主线程中

  到这里就恍然大悟了,原来CCHttpClient的http请求为异步方法,进行http请求并不会堵塞cocos2dx主线程的执行。

  这种情况下一个比较好的解决思路是,我们在onHttpComplete方法中对字段进行赋值之后,同样触发一个回调方法,在外部类需要读取网络时间的地方注册该回调方法。

  (对C++回调函数不熟悉的可以参考这里:C/C++之回调函数

  为了符合cocos2dx的使用习惯,我们参考cocos2dx中常用的回调方法设计,如CCHttpRequest中的回调。

  通过查看CCHttpRequest源码可以发现,首先声明了用于调用回调方法的函数指针和用于注册回调方法的宏:

    typedef void (CCObject::*SEL_HttpResponse)(CCHttpClient* client, CCHttpResponse* response);
       #define httpresponse_selector(_SELECTOR) (cocos2d::extension::SEL_HttpResponse)(&_SELECTOR) 

  setResponseCallback进行回调方法注册的实现如下,两个参数分别为回调方法的调用者和函数指针

   inline void setResponseCallback(CCObject* pTarget, SEL_HttpResponse pSelector)
       {
           _pTarget = pTarget;
           _pSelector = pSelector;
       
            if (_pTarget)
            {
                _pTarget->retain();
            }
       } 

  然后通过CCHttpClicent的send(CCHttpRequest* request)方法传入CCHttpRequest的实例,在异步请求Http完成后,调用注册的回调方法返回给我们Http请求的状态和数据。

  初步了解了cocos2dx中回调的实现后,回到我们的NetTime中,在NetTime.h头文件中声明函数指针和用于注册的宏定义: 

  

typedef void (CCObject::*SEL_NetTime)(WebTime * pSender);#define netTime_selector(_SELECTOR) (SEL_NetTime)(&_SELECTOR)

  同时声明用于存放调用者实例和函数指针的字段:  

SEL_NetTime _pSelector;
CCObject * _pTarget;

  通过重载requestNetTime方法传入回调方法的调用者和函数指针: 

void NetTime::requestNetTime(CCObject * pTarget, SEL_NetTime pSelector)
{
    requestNetTime();
    _pTarget = pTarget;
    _pSelector = pSelector;
}

  在onHttpComplete方法的最后调用回调方法,并把NetTime的实例作为回调方法的参数:

  

 1 void NetTime::onHttpComplete(CCHttpClient * sender, CCHttpResponse * response)
 2 {
 3     CCHttpClient::getInstance()->release();
 4     if (!response)
 5         return;
 6     if (0 != strlen(response->getHttpRequest()->getTag()))
 7     {
 8         CCLog("%s completed", response->getHttpRequest()->getTag());
 9     }
10     int statusCode = response->getResponseCode();
11     char statusString[64] = {};
12     sprintf(statusString, "HTTP Status: %d, tag = %s", statusCode, response->getHttpRequest()->getTag());
13     CCLog("%s", statusString);
14     if (!response->isSucceed())
15     {
16         CCLog("response failed");
17         CCLog("error buffer:%s", response->getErrorBuffer());
18         return;
19     }
20     std::vector<char> * buffer = response->getResponseData();
21     std::string str;
22     for (unsigned i = 0; i < buffer->size(); i++)
23     {
24         char a = (*buffer)[i];
25         str.append(1, a);
26     }
27     CCLog("%s", str.c_str());
28     readJson(str);
29     if (_pTarget&&_pSelector)
30     {
31         (_pTarget->*_pSelector)(this);
32     }
33 }

  到这里便完成了对NetTime类的封装。

  再来修改HelloWorldSecne中对NetTime使用的代码:

  

1 NetTime * netTime = NetTime::create();
2 netTime->requestNetTime(this, netTime_selector(HelloWorld::onNetTimeComplete));

  onNetTimeComplete代码如下:

 1 void HelloWorld::onNetTimeComplete(NetTime * pSender)
 2 {
 3     char timeStr[50];
 4     sprintf(timeStr, "NetTime  %d-%d-%d %d:%d:%d",
 5         pSender->getYear(), pSender->getMonth(), pSender->getDay(),
 6         pSender->getHour(), pSender->getMinute(), pSender->getSecond());
 7     CCLabelTTF *timeLabel = CCLabelTTF::create(timeStr, "Arial", 18);
 8     timeLabel->setPosition(ccp(240, 50));
 9     this->addChild(timeLabel);
10 }

  调试结果: 

  

  和上一篇文章的结果是一致的。

  Demo下载:NetTime(2).zip

  

  

  

时间: 2024-11-08 20:36:55

cocos2dx获取网络时间(二):浅析CCHttpClient的相关文章

cocos2dx获取网络时间(一)

今天在公司的cocos2dx项目中遇到一个需求,需要获取网络时间和系统时间对比,目的是防止用户更改系统时间进行某些非法操作 . 那么cocos2dx怎么来获取网络时间呢 ?我整理的思路如下: (1)由一个web api可以返回当前的网络时间 (2)cocos2dx通过http请求该api获取数据到本地 (3)cocos2dx解析数据得到当前的网络时间 一:首先就需要一个web接口来提供网络时间的数据,我在这里自己搭建一个WCF服务返回需要的数据. 新建WCF服务应用程序 , 项目命名为NetTi

多方法获取网络时间

转自:http://blog.csdn.net/xiaoxian8023/article/details/7250385 在做YH维护的时候,偶尔会碰到这样的问题:电脑的非正常关机导致系统时间出错(变为了2002-1-1),从而影响到项目系统的使用.尤其是设计到money的系统,如果时间错误,可能会导致无法想象的后果.所以我们可能需要用系统和网络的双重验证. 通过收集.修改.优化和测试,剔除了一些错误的和速度超慢的,只剩下了4种可行的方案.这些方案中主要有3类: 一.通过向某网站发送请求,获取服

.net 获取网络时间(北京时间)24小时制

/// <summary> /// 更新系统时间 /// </summary> public class UpdateTime { //设置系统时间的API函数 [DllImport("kernel32.dll")] private static extern bool SetLocalTime(ref SYSTEMTIME time); [StructLayout(LayoutKind.Sequential)] private struct SYSTEMTIM

实时获取网络时间 并转换为北京时间的函数

unit Unit1; interface uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs,Winapi.msxml, System.DateUtils, Vcl.StdCtrls; type TForm1 = class(TForm) Button1: TButton

获取网络时间

这两天有一个应用需要获取网络时间,虽然一直知道可以从时间服务器获取时间,却从来也没有操作过,借这个机会重新进行一下深入了了解. 基本的思路就是:通过SOCKET连接时间服务器,直接接收从服务器发送的过来的时间数据. void GetNetTime() { TIME_ZONE_INFORMATION tzinfo; DWORD dwStandardDaylight; int nRet; /* Get server IP */ struct hostent *host; char *pServerI

cocos2dx 获取当前时间

终于有时间再来学习STM32了~ 这几天都在忙着该死的考试.直接进入正题 开发板:奋斗V5 这个按键中断测试的要求是:按键2(K2)按下,LED2(V7)亮, 再一次按下就灭,循环.. 好,先看看按键和LED的原理图 好吧~ 虽然图截得不是很好看,但是能看到K2接的是PC2, LED2接的是PD6 ok,剩下的就是配置工作了.. 先来理一理思路: (1)初始化系统时钟 (2)初始化外部时钟(你所用到的东西) (3)配置LED (4)配置中断优先级 (5)配置外部中断线 (6)中断处理函数 恩,差

iOS获取网络时间与转换格式

[NSDate date]可以获取系统时间,但是会造成一个问题,用户可以自己修改手机系统时间,所以有时候需要用网络时间而不用系统时间.获取网络标准时间的方法: 1.先在需要的地方实现下面的代码,创建一个URL并且连接 1 NSURL *url=[NSURL URLWithString:@"http://www.baidu.com"]; 2 NSURLRequest *request=[NSURLRequest requestWithURL:url]; 3 NSURLConnection

获取网络时间失败,求大神指点

private void GainTime() { new Thread(new Runnable() { @Override public void run() { try { URL url=new URL("http://www.taobao.com"); URLConnection uc=url.openConnection(); uc.connect(); long id=uc.getDate(); Date date=new Date(id); SimpleDateForm

c#获取网络时间并同步本地时间

通过TCP形式来获取NTP时间.主要代码如下: [DllImport("kernel32.dll")] private static extern bool SetLocalTime(ref Systemtime time); [StructLayout(LayoutKind.Sequential)] private struct Systemtime { public short year; public short month; public short dayOfWeek; pu