• cocos2d-x游戏引擎核心之十——网络通信


    一、建立基本的http通信并得到返回信息

    1、创建cocos2dx工程

    2、项目引用外部库

    如果要使用cocos2dx的CCHttpClient来进行网络访问,则需要引入cocos2dx的相关库,详细步骤如下:

    右键单击项目->属性->c/c++->常规,在右边的附件包含目录中添加cocos2dx的extensions目录对应的路径。

    然后,右键单击项目->属性->链接器->输入,在右边的附件依赖项中添加libcurl_imp.lib和libExtensions.lib两个库,用分号隔开。

    如果不引入extensions文件夹,会出现找不到CCHttpClient的错误;如果不引入libcurl_imp.lib和libExtensions.lib两个库,编译项目时也会出现报错。另外注意引入头文件:

    #include "cocos-ext.h"  

    3.添加下载按钮和回调函数

    CCMenuItemImage *pDownloadItem = CCMenuItemImage::create(  
                "bt_blue_light.png",  
                "bt_blue_light.png",  
                this,  
                menu_selector(HelloWorld::menuDownloadCallback)  
            );  
            CC_BREAK_IF(!pDownloadItem);  
            CCSize pWinSize = CCDirector::sharedDirector()->getWinSize();  
          
            CCMenu* pDownloadMenu = CCMenu::create(pDownloadItem, NULL);  
            pDownloadMenu->setPosition(ccp(50  ,50));  
            CC_BREAK_IF(! pDownloadMenu);  
            this->addChild(pDownloadMenu, 1);

    添加按钮的回调函数:

    void HelloWorld::menuDownloadCallback(CCObject* pSender)  
    {  
        cocos2d::extension::CCHttpRequest* request = new cocos2d::extension::CCHttpRequest();  
        request->setUrl("http://www.oschina.net/action/api/news_list");  
        request->setRequestType(cocos2d::extension::CCHttpRequest::kHttpPost);  
        std::vector<std::string> headers;  
        headers.push_back("Content-Type: application/json; charset=utf-8");  
        request->setHeaders(headers);  
        const char* postData = "catalog=2&pageIndex=1&pageSize=5";  
        request->setRequestData(postData ,strlen(postData));  
        request->setResponseCallback(this, callfuncND_selector(HelloWorld::onHttpRequestCompleted));  
        request->setTag("Post_My_Data");  
        cocos2d::extension::CCHttpClient::getInstance()->send(request);  
        request->release();  
    }  

    按钮的回调函数里向服务器发起http请求了,request->setResponseCallback(this, callfuncND_selector(HelloWorld::onHttpRequestCompleted))一行代码,向请求结束时添加了onHttpRequestCompleted回调函数:

    4.为http request 结束增加回调函数并读取网络数据

    void HelloWorld::onHttpRequestCompleted(cocos2d::CCNode *sender ,void *data)  
    {  
        AllocConsole();  
        freopen("CONIN$", "r", stdin);  
        freopen("CONOUT$", "w", stdout);  
        freopen("CONOUT$", "w", stderr);  
        cocos2d::extension::CCHttpResponse *response = (cocos2d::extension::CCHttpResponse*)data;    
         if (!response)    
        {  
            return;    
        }   
         if (0 != strlen(response->getHttpRequest()->getTag()))   
        {  
            CCLog("%s completed", response->getHttpRequest()->getTag());  
        }  
         int statusCode = response->getResponseCode();  
         char statusString[64] = {};  
         sprintf(statusString ,"Http status code:%d ,tag = %s" ,statusCode ,response->getHttpRequest()->getTag());  
         CCLog("response code:%d" ,statusCode);  
         if (!response->isSucceed())  
         {  
             CCLog("response failed");  
             CCLog("error buffer:%s" ,response->getErrorBuffer());  
         }  
         std::vector<char> *buffer = response->getResponseData();  
         printf("Http response,dump data:");  
         std::string result = "";  
         for (unsigned int i = 0; i < buffer->size(); i ++)  
         {  
            printf("%c" ,(*buffer)[i]);  
         }  
    }  

    debug时就能看到reponse中服务器返回的数据了

    :上面操作遇到的问题

    (1) 1>libExtensions.lib(HttpClient.obj) : error LNK2019: 无法解析的外部符号 __imp__pthread_create,该符号在函数 "private: bool __thiscall cocos2d::extension::CCHttpClient::lazyInitThreadSemphore(void)" (?lazyInitThreadSemphore@CCHttpClient@extension@cocos2d@@AAE_NXZ) 中被引用。

    解决方法:刚开始这里我是不理解的,因为我以为lib库只需要添加一个libExtensions.lib就行...其实还需要其他俩个lib库文件,pthreadVCE2.lib,libcurl_imp.lib,添加方法(Vs2012):项目属性->链接器->输入->附加依赖项。

    (2)error LNK2038: 检测到“_ITERATOR_DEBUG_LEVEL”的不匹配项: 值“0”不匹配值“2”

    error:
    vtkCommon.lib(vtkSmartPointerBase.obj) : error LNK2038: 检测到“_ITERATOR_DEBUG_LEVEL”的不匹配项:值“0”不匹配值“2”(cloudviewer.obj 中)
    1>vtkCommon.lib(vtkGarbageCollector.obj) : error LNK2038: 检测到“_ITERATOR_DEBUG_LEVEL”的不匹配项: 值“0”不匹配值“2”(cloudviewer.obj 中)
    1>vtkCommon.lib(vtkDebugLeaksManager.obj) : error LNK2038: 检测到“_ITERATOR_DEBUG_LEVEL”的不匹配项: 值“0”不匹配值“2”(cloudviewer.obj 中)
     
    错误原因是:Debug使用了Release的库文件。
    即使你连接库里面两个都添加着呢,但是release库文件放在了debug前面,也是出错的。默认按顺序使用库文件。
    类似错误:如release下使用了Debug的库文件,报错类似:
    error LNK2038: 检测到“_ITERATOR_DEBUG_LEVEL”的不匹配项: 值“2”不匹配值“0”.
    解决方法:把Debug模式改为Release模式,编译生成之后,在项目文件夹中运行.exe文件(这里还报了找不到图片资源的错误,把图片资源拷贝到.exe文件同等目录下则可)

     

    #ifndef __HELLOWORLD_SCENE_H__
    #define __HELLOWORLD_SCENE_H__
    
    #include "cocos2d.h"
    
    #include "SimpleAudioEngine.h"
    #include "cocos-ext.h" 
    
    class HelloWorld : public cocos2d::CCLayer
    {
    public:
        // Here's a difference. Method 'init' in cocos2d-x returns bool, instead of returning 'id' in cocos2d-iphone
        virtual bool init();  
    
        // there's no 'id' in cpp, so we recommand to return the exactly class pointer
        static cocos2d::CCScene* scene();
        
        // a selector callback
        void menuCloseCallback(CCObject* pSender);
    
        void onHttpRequestCompleted(cocos2d::CCNode *sender ,void *data);
    
    
        // implement the "static node()" method manually
        CREATE_FUNC(HelloWorld);
    };
    
    #endif  // __HELLOWORLD_SCENE_H__
    #include "HelloWorldScene.h"
    
    using namespace cocos2d;
    
    CCScene* HelloWorld::scene()
    {
        CCScene * scene = NULL;
        do 
        {
            // 'scene' is an autorelease object
            scene = CCScene::create();
            CC_BREAK_IF(! scene);
    
            // 'layer' is an autorelease object
            HelloWorld *layer = HelloWorld::create();
            CC_BREAK_IF(! layer);
    
            // add layer as a child to scene
            scene->addChild(layer);
        } while (0);
    
        // return the scene
        return scene;
    }
    
    // on "init" you need to initialize your instance
    bool HelloWorld::init()
    {
        bool bRet = false;
        do 
        {
            //////////////////////////////////////////////////////////////////////////
            // super init first
            //////////////////////////////////////////////////////////////////////////
    
            CC_BREAK_IF(! CCLayer::init());
    
            //////////////////////////////////////////////////////////////////////////
            // add your codes below...
            //////////////////////////////////////////////////////////////////////////
    
            // 1. Add a menu item with "X" image, which is clicked to quit the program.
    
            // Create a "close" menu item with close icon, it's an auto release object.
            CCMenuItemImage *pCloseItem = CCMenuItemImage::create(
                "CloseNormal.png",
                "CloseSelected.png",
                this,
                menu_selector(HelloWorld::menuCloseCallback));
            CC_BREAK_IF(! pCloseItem);
    
            // Place the menu item bottom-right conner.
            pCloseItem->setPosition(ccp(CCDirector::sharedDirector()->getWinSize().width - 20, 20));
    
            // Create a menu with the "close" menu item, it's an auto release object.
            CCMenu* pMenu = CCMenu::create(pCloseItem, NULL);
            pMenu->setPosition(CCPointZero);
            CC_BREAK_IF(! pMenu);
    
            // Add the menu to HelloWorld layer as a child layer.
            this->addChild(pMenu, 1);
    
            // 2. Add a label shows "Hello World".
    
            // Create a label and initialize with string "Hello World".
            CCLabelTTF* pLabel = CCLabelTTF::create("Hello World", "Arial", 24);
            CC_BREAK_IF(! pLabel);
    
            // Get window size and place the label upper. 
            CCSize size = CCDirector::sharedDirector()->getWinSize();
            pLabel->setPosition(ccp(size.width / 2, size.height - 50));
    
            // Add the label to HelloWorld layer as a child layer.
            this->addChild(pLabel, 1);
    
            // 3. Add add a splash screen, show the cocos2d splash image.
            CCSprite* pSprite = CCSprite::create("HelloWorld.png");
            CC_BREAK_IF(! pSprite);
    
            // Place the sprite on the center of the screen
            pSprite->setPosition(ccp(size.width/2, size.height/2));
    
            // Add the sprite to HelloWorld layer as a child layer.
            this->addChild(pSprite, 0);
    
            bRet = true;
        } while (0);
    
        return bRet;
    }
    
    void HelloWorld::menuCloseCallback(CCObject* pSender)
    {
        // "close" menu item clicked
        //CCDirector::sharedDirector()->end();
        cocos2d::extension::CCHttpRequest* request = new cocos2d::extension::CCHttpRequest();  
        request->setUrl("http://www.oschina.net/action/api/news_list");  
        request->setRequestType(cocos2d::extension::CCHttpRequest::kHttpPost);  
        std::vector<std::string> headers;  
        headers.push_back("Content-Type: application/json; charset=utf-8");  
        request->setHeaders(headers);  
        const char* postData = "catalog=2&pageIndex=1&pageSize=5";  
        request->setRequestData(postData ,strlen(postData));  
        request->setResponseCallback(this, callfuncND_selector(HelloWorld::onHttpRequestCompleted));  
        request->setTag("Post_My_Data");  
        cocos2d::extension::CCHttpClient::getInstance()->send(request);  
        request->release(); 
    
    }
    
    void HelloWorld::onHttpRequestCompleted(cocos2d::CCNode *sender ,void *data)  
    {  
        AllocConsole();  
        freopen("CONIN$", "r", stdin);  
        freopen("CONOUT$", "w", stdout);  
        freopen("CONOUT$", "w", stderr);  
        cocos2d::extension::CCHttpResponse *response = (cocos2d::extension::CCHttpResponse*)data;    
        if (!response)    
        {  
            return;    
        }   
        if (0 != strlen(response->getHttpRequest()->getTag()))   
        {  
            CCLog("%s completed", response->getHttpRequest()->getTag());  
        }  
        int statusCode = response->getResponseCode();  
        char statusString[64] = {};  
        sprintf(statusString ,"Http status code:%d ,tag = %s" ,statusCode ,response->getHttpRequest()->getTag());  
        CCLog("response code:%d" ,statusCode);  
        if (!response->isSucceed())  
        {  
            CCLog("response failed");  
            CCLog("error buffer:%s" ,response->getErrorBuffer());  
        }  
        std::vector<char> *buffer = response->getResponseData();  
        printf("Http response,dump data:");  
        std::string result = "";  
        for (unsigned int i = 0; i < buffer->size(); i ++)  
        {  
            printf("%c" ,(*buffer)[i]);  
        }  
    }  

    二、使用libjson来解析网络json数据

  • 相关阅读:
    使用 crontab 来定时执行脚本,无法执行,但是如果直接通过命令(如:./test.sh)又可以正常执行,
    解决RABBITMQ ADMIN账号登陆失败的问题
    Job for rabbitmq-server.service failed because the control process exited with error code. See "systemctl status rabbitmq-server.service" and "journalctl -xe" for details.
    git 删除远端分支,本地新创建分支推到远程或者 拉取远程分支并创建本地分支
    细品 Spring Boot+Thymeleaf,还有这么多好玩的细节!
    Spring Boot 日志各种使用姿势,是时候捋清楚了!
    SQL多节节点MS SQL中的递归
    支付DLL接口
    (转)ubuntu下查询CPU数,核心数,线程数
    (转)C/C++中计算程序运行时间
  • 原文地址:https://www.cnblogs.com/yyxt/p/4092538.html
Copyright © 2020-2023  润新知