cocos2d-x3.2 Socket传输Json字符串

来源:互联网 发布:河北大学新区淘宝地址 编辑:程序博客网 时间:2024/05/16 18:58

这里使用客户端用的是C++的简单封装,参考http://blog.csdn.net/langresser_king/article/details/8646088这篇文章。

原文地址:http://blog.csdn.net/qqmcy/article/details/39155541

代码下载:http://download.csdn.net/detail/qqmcy/7884273

服务器端用的JAVA编写。测试服务器代码:http://download.csdn.net/detail/qqmcy/7884327 这个服务器代码只适合测试使用。

使用方法:

HelloWorldScene.h

#ifndef __HELLOWORLD_SCENE_H__#define __HELLOWORLD_SCENE_H__#include "cocos2d.h"#include "Tools/SocketModel/DJAsyncSocket.h"class HelloWorld : public cocos2d::Layer ,public DJAsyncSocketDelegate{public:    // there's no 'id' in cpp, so we recommend returning the class instance pointer    static cocos2d::Scene* createScene();    // Here's a difference. Method 'init' in cocos2d-x returns bool, instead of returning 'id' in cocos2d-iphone    virtual bool init();          // implement the "static create()" method manually    CREATE_FUNC(HelloWorld);        void menuCloseCallback(Ref* sender);    private:    DJAsyncSocket* socket_asy;        virtual void update(float delta);        virtual void onSocketDidReadData(DJAsyncSocket* sock ,char* data);        };#endif // __HELLOWORLD_SCENE_H__

HelloWorldScene.cpp

#include "HelloWorldScene.h"#include "Tools/JsonData/MakeJson.h"USING_NS_CC;#define IP "127.0.0.1";Scene* HelloWorld::createScene(){    // 'scene' is an autorelease object    auto scene = Scene::create();        // 'layer' is an autorelease object    auto layer = HelloWorld::create();    // add layer as a child to scene    scene->addChild(layer);    // return the scene    return scene;}// on "init" you need to initialize your instancebool HelloWorld::init(){    //////////////////////////////    // 1. super init first    if ( !Layer::init() )    {        return false;    }             socket_asy = new DJAsyncSocket();    socket_asy->setDelegate(this);    socket_asy->create("127.0.0.1", 8000);                auto visibleSize = Director::getInstance()->getVisibleSize();    auto origin = Director::getInstance()->getVisibleOrigin();        auto closeItem = MenuItemImage::create(                                           "choose_btn_light.png",                                           "choose_btn_light.png",                                           CC_CALLBACK_1(HelloWorld::menuCloseCallback,this));        closeItem->setPosition(origin + Vec2(visibleSize) - Vec2(closeItem->getContentSize() / 2));        // create menu, it's an autorelease object    auto menu = Menu::create(closeItem, NULL);    menu->setPosition(Vec2::ZERO);    this->addChild(menu, 1);    this->scheduleUpdate();        return true;}void HelloWorld::menuCloseCallback(Ref* sender){        MakeJson* mjson = MakeJson::create();            std::string content = mjson->getTestJson();    content.append("\n");            //    const char* str_cnt = content.c_str();    int len = (int)content.length();        //"{ \"hello\" : \"world\" }";//    char* str  = nullptr;//"{\"reciver\":\"555\",\"sender\":\"f\"}\n";    char* str = (char*)malloc((len)* sizeof(char));    content.copy(str, len,0);    //    log("content = %s,length = %lu ,Len = %d",content.c_str(),strlen(str),len);     socket_asy->sendMsg(str, len);    socket_asy->flush();    //    free(str);//    content = nullptr;                    }void HelloWorld::update(float delta){        // 接收消息处理(放到游戏主循环中,每帧处理)    if (!socket_asy) {        return;    }        // 接收数据(取得缓冲区中的所有消息,直到缓冲区为空)    while (true)    {        char buffer[_MAX_MSGSIZE] = { 0 };        int nSize = sizeof(buffer);        char* pbufMsg = buffer;        if(socket_asy == NULL)        {            break;        }        if (!socket_asy->receiveMsg(pbufMsg, nSize)) {            break;        }            }        }void HelloWorld::onSocketDidReadData(DJAsyncSocket *sock, char *data){    log("data = %s",data);        auto path = FileUtils::getInstance()->getWritablePath();    log("%s",path.c_str());        //在这个路径下添加一个json文件    path.append("test.json");        FILE* file = fopen(path.c_str(), "wb");    if (file) {        fputs(data, file);        fclose(file);    }}

DJAsyncSocket.h

////  DJAsyncSocket.h//  cpp4////  Created by 杜甲 on 14-9-5.////#ifndef __cpp4__DJAsyncSocket__#define __cpp4__DJAsyncSocket__#if WIN32#include <windows.h>#include <WinSock.h>#else#include <sys/socket.h>#include <fcntl.h>#include <errno.h>#include <netinet/in.h>#include <arpa/inet.h>#include <string.h>#include <sys/stat.h>#include <unistd.h>#define SOCKET int#define SOCKET_ERROR  -1#define INVALID_SOCKET -1#endif#ifndef CHECHF#define CHECKF(x) \do \{ \if(!(x)) {\log("CHECK",#x,__FILE__,__LINE__);\return 0; \}\} while(0)#endif#define  _MAX_MSGSIZE   8 * 1024       //暂定一个消息最大为16K#define BLOCKSECONDS        30          //INIT函数阻塞时间#define INBUFSIZE       (64 * 1024)     //  接收数据缓存#define OUTBUFSIZE      (8  * 1024)     //  发送数据的缓存,当不超过8K时,FLUSH只需要SEND一次#include "cocos2d.h"USING_NS_CC;class DJAsyncSocket;class DJAsyncSocketDelegate{public:     virtual void onSocketDidReadData(DJAsyncSocket* sock ,char* data) = 0;};class DJAsyncSocket :public Ref{public:    DJAsyncSocket();        bool create(const char* pszServerIP , int nServerPort , int nBlockSec = BLOCKSECONDS , bool bKeepAlice = false);    bool sendMsg(void* pBuf , int nSize);    bool receiveMsg(void* pBuf , int& nSize);    bool flush(void);    bool check(void);    void destory(void);        SOCKET getSocket(void) const ;private:    CC_SYNTHESIZE(DJAsyncSocketDelegate*, _delegate, Delegate);        bool recvFromSock(void);    //从网络中读取尽可能多的数据    bool hasError(void);    //是否发生错误,注意,异步模式未完成非错误    void closeSocket(void);        SOCKET  m_sockClient;        //发送数据缓冲    char    m_bufOutput[OUTBUFSIZE];    int     m_nOutbufLen;            //环形缓冲区    char    m_bufInput[INBUFSIZE];    int     m_nInbufLen;    int     m_nInbufStart;          //INBUF使用循环式队列,该变量为队列起点,0 - (SIZE  - 1)};#endif /* defined(__cpp4__DJAsyncSocket__) */


DJAsyncSocket.cpp

////  DJAsyncSocket.cpp//  cpp4////  Created by 杜甲 on 14-9-5.////#include "DJAsyncSocket.h"DJAsyncSocket::DJAsyncSocket(){    //初始化    memset(m_bufOutput, 0, sizeof(m_bufOutput));    memset(m_bufInput, 0, sizeof(m_bufInput));}void DJAsyncSocket::closeSocket(){#ifdef WIN32    closeSocket(m_sockClient);     WSACleanup();#else    close(m_sockClient);#endif}bool DJAsyncSocket::create(const char *pszServerIP, int nServerPort, int nBlockSec, bool bKeepAlive /*= FALSE*/){    if (pszServerIP == 0 || strlen(pszServerIP) > 15) {        return false;    }#ifdef WIN32WSADATA wsaData;WORD version = MAKEWORD(2, 0);int ret = WSAStartup(version, &wsaData);//win sock start upif (ret != 0) {return false;}#endif        //  创建主套接字    m_sockClient = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);    if (m_sockClient == INVALID_SOCKET) {        closeSocket();        return false;    }        //设置Socket为KEEPALIVE    if (bKeepAlive)    {        int optval = 1;        if (setsockopt(m_sockClient, SOL_SOCKET, SO_KEEPALIVE, (char*)& optval , sizeof(optval))) {            closeSocket();            return false;        }    }    #ifdef WIN32DWORD nMode = 1;int nRes = ioctlsocket(m_sockClient, FIONBIO, &nMode);if (nRes == SOCKET_ERROR) {closeSocket();return false;}#else// 设置为非阻塞方式fcntl(m_sockClient, F_SETFL, O_NONBLOCK);#endif        unsigned long serveraddr = inet_addr(pszServerIP);    if (serveraddr == INADDR_NONE) {    //检查IP地址格式错误        closeSocket();        return false;    }        sockaddr_in addr_in;    memset((void*)& addr_in, 0, sizeof(addr_in));        addr_in.sin_family = AF_INET;    addr_in.sin_port   = htons(nServerPort);    addr_in.sin_addr.s_addr = serveraddr;        if (connect(m_sockClient, (sockaddr*)& addr_in, sizeof(addr_in)) == SOCKET_ERROR) {        if (hasError()) {            closeSocket();            return false;        }        else    // WSAWOLDBLOCK        {            timeval timeout;            timeout.tv_sec = nBlockSec;            timeout.tv_usec = 0;            fd_set writeset,exceptset;                        FD_ZERO(&writeset);            FD_ZERO(&exceptset);            FD_SET(m_sockClient, &writeset);            FD_SET(m_sockClient, &exceptset);                        int ret = select(FD_SETSIZE, NULL, &writeset, &exceptset, &timeout);            if (ret == 0 || ret < 0) {                closeSocket();                return false;            }else   //ret > 0            {                ret = FD_ISSET(m_sockClient, &exceptset);                if (ret) {                    closeSocket();                    return false;                }            }                    }    }    m_nInbufLen     = 0;    m_nInbufStart   = 0;    m_nOutbufLen    = 0;        struct linger so_linger;    so_linger.l_onoff   = 1;    so_linger.l_linger  = 500;    setsockopt(m_sockClient, SOL_SOCKET, SO_LINGER, (const char*)& so_linger, sizeof(so_linger));        return true;}bool DJAsyncSocket::hasError(){#ifdef WIN32int err = WSAGetLastError();if(err != WSAEWOULDBLOCK) {        return true;    }        #else    int err = errno;    if(err != EINPROGRESS && err != EAGAIN) {        return true;    }    #endif        return false;}bool DJAsyncSocket::sendMsg(void *pBuf, int nSize){    if (pBuf == 0 || nSize <= 0) {        return false;    }        if (m_sockClient == INVALID_SOCKET) {        return false;    }        //检查通讯消息包长度    int packsize = 0;    packsize = nSize;        //检测BUF溢出    if (m_nOutbufLen + nSize > OUTBUFSIZE) {        //立即发送OUTBUF中的数据,以清空OUTBUF        flush();        if (m_nOutbufLen + nSize > OUTBUFSIZE) {            destory();            return false;        }    }        memcpy(m_bufOutput + m_nOutbufLen, pBuf, nSize);    m_nOutbufLen += nSize;        return true;}bool DJAsyncSocket::flush(){    if (m_sockClient == INVALID_SOCKET) {        return false;    }        if (m_nOutbufLen <= 0) {        return true;    }        //发送一段数据    int outsize;        outsize = send(m_sockClient, m_bufOutput, m_nOutbufLen, 0);    if (outsize > 0){        //删除已发送的部分        if (m_nOutbufLen - outsize > 0) {            memcpy(m_bufOutput, m_bufOutput + outsize, m_nOutbufLen - outsize);        }        m_nOutbufLen -= outsize;        if (m_nOutbufLen < 0) {            return false;        }                    }else{        if (hasError()) {            destory();            return false;        }    }    return true;}bool DJAsyncSocket::check(){    //检查状态    if (m_sockClient == INVALID_SOCKET) {        return false;    }                char buf[1];    int ret = recv(m_sockClient, buf, 1, MSG_PEEK);    if (ret == 0) {        destory();        return false;    }else if (ret < 0){        if (hasError()) {            destory();            return false;        }else{            return true;        }    }else{        return true;    }        return true;}bool DJAsyncSocket::receiveMsg(void *pBuf, int &nSize){    //检查参数    if (pBuf == NULL || nSize <= 0) {        return false;    }        if (m_sockClient == INVALID_SOCKET) {        return false;    }//     log("m_bufInput = %s,m_nInbufLen = %d",m_bufInput,m_nInbufLen);    //检查是否有一个消息(小于2则无法获取到消息长度)    if (m_nInbufLen < 2) {        //  如果没有请求成功    或者  如果没有数据则直接返回        if (!recvFromSock() || m_nInbufLen < 2) {   //这个m_nInbufLen更新了                        return false;        }    }        if (_delegate) {        _delegate->onSocketDidReadData(this, m_bufInput);    }           //计算要拷贝的消息的大小(一个消息,大小为整个消息的第一个16字节),因为环形缓冲区,所以要分开结算    int packsize = (unsigned char) m_bufInput[m_nInbufStart] + (unsigned char)m_bufInput[(m_nInbufStart + 1) % INBUFSIZE] * 256;    //注意字节序,高位 + 低位    //检测消息包尺寸错误 暂定最大16k    if (packsize <= 0 || packsize > _MAX_MSGSIZE) {        m_nInbufLen     = 0;    //直接清空INBUF        m_nInbufStart   = 0;        return false;    }        //检查消息是否完整(如果将要拷贝的消息大于此时缓冲区数据长度,需要再次请求接收剩余数据)        if (packsize > m_nInbufLen) {        //如果没有请求成功      或者  依然无法获取到完整的数据包   则返回,直到取得wanzbao        if (!recvFromSock() || packsize > m_nInbufLen) {    //这个m_nInbufLen已更新            return false;        }    }                    //  复制出一个消息    if (m_nInbufStart + packsize > INBUFSIZE) {        //  如果一个消息有回卷(被拆成两份在环形缓冲区的头尾)        //  先拷贝环形缓冲区末尾的数据        int copylen = INBUFSIZE - m_nInbufStart;        memcpy(pBuf, m_bufInput + m_nInbufStart, copylen);                //再考贝环形缓冲区头部的剩余部分        memcpy((unsigned char*) pBuf + copylen, m_bufInput, packsize - copylen);        nSize = packsize;    }else    {        //  消息没有回卷,可以一次拷贝出去        memcpy(pBuf, m_bufInput + m_nInbufStart, packsize);        nSize = packsize;    }//    log("m_bufInput = %s",m_bufInput);    m_nInbufStart = (m_nInbufStart + packsize) % INBUFSIZE;    m_nOutbufLen -= packsize;    return true;}bool DJAsyncSocket::recvFromSock(){    if (m_nInbufLen >= INBUFSIZE || m_sockClient == INVALID_SOCKET) {        return false;    }        //接收第一段数据    int savelen , savepos;          //数据要保存的长度和位置    if (m_nInbufStart + m_nInbufLen < INBUFSIZE) {  //INBUF中的剩余空间有回绕        savelen = INBUFSIZE - (m_nInbufStart + m_nInbufLen);    //后部空间长度,最大接收数据的长度    }else{        savelen = INBUFSIZE - m_nInbufLen;    }        //  缓冲区数据的末尾    savepos = (m_nInbufStart + m_nInbufLen) % INBUFSIZE;//    CHECKF(savepos + savelen < INBUFSIZE);    int inlen = recv(m_sockClient, m_bufInput + savepos, savelen, 0);                if (inlen > 0) {        //有接收到数据        m_nInbufLen += inlen;                if (m_nInbufLen > INBUFSIZE) {            return false;        }                //接收第二段数据(一次接收没有完成,接收第二段数据)        if (inlen == savelen && m_nInbufLen < INBUFSIZE) {            int savelen = INBUFSIZE - m_nInbufLen;            int savepos = (m_nInbufStart + m_nInbufLen) % INBUFSIZE;//            CHECKF(savepos + savelen <= INBUFSIZE);            inlen = recv(m_sockClient, m_bufInput + savepos, savelen, 0);            if (inlen > 0) {                m_nInbufLen += inlen;                if (m_nInbufLen > INBUFSIZE) {                    return false;                }            }else if (inlen == 0){                destory();                return false;            }else{                if (hasError()) {                    destory();                    return false;                }            }        }            }        return true;}void DJAsyncSocket::destory(){    //  关闭    struct linger so_linger;    so_linger.l_onoff       = 1;    so_linger.l_linger      = 500;    int ret = setsockopt(m_sockClient, SOL_SOCKET, SO_LINGER, (const char*)& so_linger, sizeof(so_linger));        closeSocket();    m_sockClient  = INVALID_SOCKET;    m_nInbufLen   = 0;    m_nInbufStart = 0;    m_nOutbufLen  = 0;        memset(m_bufOutput, 0, sizeof(m_bufOutput));    memset(m_bufInput,  0, sizeof(m_bufInput));}

下面是制作JSON数据的类

MakeJson.h

////  MakeJson.h//  cpp4////  Created by 杜甲 on 14-9-9.////#ifndef __cpp4__MakeJson__#define __cpp4__MakeJson__#include "cocos2d.h"#include "json/document.h"#include "json/writer.h"#include "json/stringbuffer.h"USING_NS_CC;class MakeJson : public Ref{public:    CREATE_FUNC(MakeJson);        virtual bool init();    std::string getTestJson();         };#endif /* defined(__cpp4__MakeJson__) */

MakeJson.cpp

////  MakeJson.cpp//  cpp4////  Created by 杜甲 on 14-9-9.////#include "MakeJson.h"bool MakeJson::init(){    bool bRef = false;    do {        bRef = true;    } while (0);    return bRef;}std::string MakeJson::getTestJson(){           rapidjson::Document d1;    d1.SetObject();    rapidjson::Document::AllocatorType& allocator = d1.GetAllocator();    rapidjson::Value array(rapidjson::kArrayType);    rapidjson::Value object(rapidjson::kObjectType);        //    object.AddMember("id", 1, allocator);//    object.AddMember("name", "xiaonan", allocator);//    object.AddMember("age", "111", allocator);//    array.PushBack(object, allocator);    d1.AddMember("reciver", "111", allocator);    d1.AddMember("sender", "111", allocator);    d1.AddMember("content", "神奇dfsa", allocator);    //    d1.AddMember("player", array, allocator);        rapidjson::StringBuffer buffer;    rapidjson::Writer<rapidjson::StringBuffer> write(buffer);    d1.Accept(write);    return StringUtils::format("%s",buffer.GetString());        }






0 0