cocos2d-x3.2 Socket传输Json字符串
这里使用客户端用的是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/7884273 这个服务器代码只适合测试使用。
使用方法:
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 instance bool 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 // 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 WIN32 WSADATA wsaData; WORD version = MAKEWORD(2, 0); int ret = WSAStartup(version, &wsaData);//win sock start up if (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 WIN32 DWORD 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 WIN32 int 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()); }
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。