操作系统:win10 64位
vs版本:2017
python版本:2.7
Cocos2d-x版本:3.17
都不是底层的socket通信;所以要自己写tcp socket通信类,而且要跨android平台的话要借助NDK,里面有各种需要的头文件
可以根据自己的需求进行封装,懒得自己写直接到网上找;
使用的时候,将client定义在AppDelegate中,这样在整个应用的生命周期中都可以使用;
#ifndef _APP_DELEGATE_H_
#define _APP_DELEGATE_H_
#include "cocos2d.h"
#include "SocketClient.h"
/**
@brief The cocos2d Application.
Private inheritance here hides part of interface from Director.
*/
class AppDelegate : private cocos2d::Application
{
private:
public:
SocketClient * _client;
AppDelegate();
virtual ~AppDelegate();
virtual void initGLContextAttrs();
/**
@brief Implement Director and Scene init code here.
@return true Initialize success, app continue.
@return false Initialize failed, app terminate.
*/
virtual bool applicationDidFinishLaunching();
/**
@brief Called when the application moves to the background
@param the pointer of the application
*/
virtual void applicationDidEnterBackground();
/**
@brief Called when the application reenters the foreground
@param the pointer of the application
*/
virtual void applicationWillEnterForeground();
/*
@brief init socket connect
*/
void initConnect();
void onRecv(const char* data, int count);
void onDisconnect();
};
#endif // _APP_DELEGATE_H_
void AppDelegate::initConnect()
{
_client = SocketClient::construct();
_client->onRecv = CC_CALLBACK_2(AppDelegate::onRecv, this);
_client->onDisconnect = CC_CALLBACK_0(AppDelegate::onDisconnect, this);
if (!_client->connectServer("127.0.0.1", 20896))
{
log("Client connect error");
}
}
/*do with meassages*/
void AppDelegate::onRecv(const char* data, int count)
{
u_int PackLength;
DataBuffer.append(data, count);
for (;;)
{
//这里对data进行处理,count为data的字节长度
}
}
void AppDelegate::onDisconnect()
{
log("Client disconnect");
}
例如在某个场景中需要发送数据时可以这样写:
AppDelegate* app = (AppDelegate *)Application::getInstance();
char head[5] = { 0 };
head[0] = 0x17; head[1] = 0x01;
head[2] = 5; head[3] = 0x00;
head[4] = i1 * 16 + j1;
app->_client->sendMessage(head, sizeof(head));
而在接收到某些数据后需要场景做出反应,可以使用自定义事件来实现;
以注册为例,在注册场景中通过sendMessage()将用户名密码发送给服务器,服务器处理完后把结果返回,在AppDelegate的onrecv函数中
void AppDelegate::regEventDispatcher(u_int type)
{
int a = type;
EventCustom event("user_reg_event");
event.setUserData(static_cast(&a));
Director::getInstance()->getEventDispatcher()->dispatchEvent(&event);
}
void AppDelegate::onRecv(const char* data, int count)
{
u_int PackLength;
DataBuffer.append(data, count);
for (;;)
{
if (DataBuffer.length() < 4)
break;
if ((PackLength = (u_char)DataBuffer[2] + ((u_char)DataBuffer[3]) * 256) > DataBuffer.length())
break;
switch ((u_char)DataBuffer[0])
{
case 0x72:
if (DataBuffer[1] < 0x03)
regEventDispatcher((u_int)DataBuffer[1]);
else
changeKeyEventDispatcher((u_int)DataBuffer[1]);
break;
default:
break;
}
if (DataBuffer.length() == PackLength)
{
DataBuffer = "";
break;
}
else
DataBuffer = DataBuffer.substr(PackLength);
}
}
在reg场景中init函数中定义
_listener = EventListenerCustom::create("user_reg_event", [=](EventCustom* event) {
int* eventSign = static_cast(event->getUserData());
switch (*eventSign)
{
case 0:messageBox->setString("Username Existed!"); break;
case 1:
messageBox->setString("Success!");
this->scheduleOnce(schedule_selector(RegScene::EnterLoginScene), 1.0f); break;
default:
break;
}
//CC_SAFE_DELETE(eventSign);
});
Director::getInstance()->getEventDispatcher()->addEventListenerWithFixedPriority(_listener, 1);
#ifndef __SOCKET_BASE_H__
#define __SOCKET_BASE_H__
#include "cocos2d.h"
#include
#include
USING_NS_CC;
#if (CC_TARGET_PLATFORM == CC_PLATFORM_WIN32)
#include
#pragma comment(lib, "WS2_32.lib")
#define HSocket SOCKET
#elif (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)
#include
#include // for inet_**
#include // for gethost**
#include // for sockaddr_in
#include // for socket
#include // for socket
#include
#include // for printf
#include // for exit
#include // for bzero
#include
#define HSocket int
#endif
enum MessageType
{
DISCONNECT,
RECEIVE,
NEW_CONNECTION
};
class SocketMessage
{
private:
MessageType msgType;
Data* msgData;
public:
SocketMessage(MessageType type, unsigned char* data, int dataLen)
{
msgType = type;
msgData = new Data;
msgData->copy(data, dataLen);
}
SocketMessage(MessageType type)
{
msgType = type;
msgData = nullptr;
}
Data* getMsgData() { return msgData; }
MessageType getMsgType() { return msgType; }
~SocketMessage()
{
if (msgData)
CC_SAFE_DELETE(msgData);
}
};
class SocketBase : public Ref
{
public:
SocketBase();
~SocketBase();
bool nonBlock(HSocket socket);
protected:
void closeConnect(HSocket socket);
bool error(HSocket socket);
protected:
std::mutex _mutex;
private:
bool _bInitSuccess;
};
#endif
#include "SocketBase.h"
SocketBase::SocketBase()
{
_bInitSuccess = false;
#if (CC_TARGET_PLATFORM == CC_PLATFORM_WIN32)
WORD wVersionRequested;
wVersionRequested = MAKEWORD(2, 0);
WSADATA wsaData;
int nRet = WSAStartup(wVersionRequested, &wsaData);
if (nRet != 0)
{
fprintf(stderr, "Initilize Error!\n");
return;
}
_bInitSuccess = true;
#endif
}
SocketBase::~SocketBase()
{
#if (CC_TARGET_PLATFORM == CC_PLATFORM_WIN32)
if (_bInitSuccess)
{
WSACleanup();
}
#endif
}
void SocketBase::closeConnect(HSocket socket)
{
#if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)
close(socket);
#elif (CC_TARGET_PLATFORM == CC_PLATFORM_WIN32)
closesocket(socket);
#endif
}
bool SocketBase::error(HSocket socket)
{
#if (CC_TARGET_PLATFORM == CC_PLATFORM_WIN32)
return socket == SOCKET_ERROR;
#elif (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)
return socket < 0;
#endif
}
bool SocketBase::nonBlock(HSocket socket)
{
#if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)
int flags;
flags = fcntl(socket, F_GETFL, 0);
flags |= O_NONBLOCK;
if (fcntl(socket, F_SETFL, flags) < 0)
{
return false;
}
#else
u_long ulOn;
ulOn = 1;
if (ioctlsocket(socket, FIONBIO, &ulOn) == SOCKET_ERROR)
{
return false;
}
#endif
return true;
}
#ifndef __SOCKET_CLIENT_H__
#define __SOCKET_CLIENT_H__
#include "SocketBase.h"
class SocketClient : public SocketBase
{
public:
static SocketClient* construct();
void destroy();
bool connectServer(const char* serverIP, unsigned short port);
void sendMessage(const char* data, int count);
std::function onRecv;
std::function onDisconnect;
void update(float dt);
CC_CONSTRUCTOR_ACCESS:
SocketClient(void);
~SocketClient(void);
private:
bool initClient();
void recvMessage();
void clear();
private:
HSocket _socketServer;
HSocket _socektClient;
std::list _UIMessageQueue;
std::mutex _UIMessageQueueMutex;
};
#endif
#include "SocketClient.h"
SocketClient* SocketClient::construct()
{
SocketClient* client = new SocketClient;
return client;
}
void SocketClient::destroy()
{
delete this;
}
SocketClient::SocketClient(void) :
onRecv(nullptr),
_socektClient(0)
{
}
SocketClient::~SocketClient(void)
{
this->clear();
}
void SocketClient::clear()
{
if (_socektClient != 0)
{
_mutex.lock();
this->closeConnect(_socektClient);
_mutex.unlock();
}
for (auto msg : _UIMessageQueue)
{
CC_SAFE_DELETE(msg);
}
_UIMessageQueue.clear();
Director::getInstance()->getScheduler()->unscheduleAllForTarget(this);
}
bool SocketClient::initClient()
{
this->clear();
_socektClient = socket(AF_INET, SOCK_STREAM, 0);
if (error(_socketServer))
{
log("init client error!");
_socektClient = 0;
return false;
}
Director::getInstance()->getScheduler()->scheduleUpdate(this, 0, false);
return true;
}
bool SocketClient::connectServer(const char* serverIP, unsigned short port)
{
if (!this->initClient())
{
return false;
}
struct sockaddr_in serverAddr;
memset(&serverAddr, 0, sizeof(struct sockaddr_in));
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(port);
serverAddr.sin_addr.s_addr = inet_addr(serverIP);
int ret = 0;
ret = connect(_socektClient, (struct sockaddr*)&serverAddr, sizeof(struct sockaddr));
if (ret < 0)
{
_socektClient = 0;
return false;
}
std::thread recvThread(&SocketClient::recvMessage, this);
recvThread.detach();
return true;
}
void SocketClient::recvMessage()
{
char recvBuf[1024];
int ret = 0;
while (true)
{
ret = recv(_socektClient, recvBuf, sizeof(recvBuf), 0);
if (ret < 0)
{
log("recv error!");
break;
}
if (ret > 0 && onRecv != nullptr)
{
std::lock_guard lk(_UIMessageQueueMutex);
SocketMessage * msg = new SocketMessage(RECEIVE, (unsigned char*)recvBuf, ret);
_UIMessageQueue.push_back(msg);
}
}
_mutex.lock();
this->closeConnect(_socektClient);
if (onDisconnect != nullptr)
{
std::lock_guard lk(_UIMessageQueueMutex);
SocketMessage * msg = new SocketMessage(DISCONNECT);
_UIMessageQueue.push_back(msg);
}
_socektClient = 0;
_mutex.unlock();
}
void SocketClient::sendMessage(const char* data, int count)
{
if (_socektClient != 0)
{
int ret = send(_socektClient, data, count, 0);
if (ret < 0)
{
log("send error!");
}
}
}
void SocketClient::update(float dt)
{
if (_UIMessageQueue.size() == 0)
{
return;
}
_UIMessageQueueMutex.lock();
if (_UIMessageQueue.size() == 0)
{
_UIMessageQueueMutex.unlock();
return;
}
SocketMessage *msg = *(_UIMessageQueue.begin());
_UIMessageQueue.pop_front();
switch (msg->getMsgType())
{
case DISCONNECT:
if (onDisconnect)
{
this->onDisconnect();
}
break;
case RECEIVE:
if (onRecv)
{
this->onRecv((const char*)msg->getMsgData()->getBytes(), msg->getMsgData()->getSize());
}
break;
default:
break;
}
CC_SAFE_DELETE(msg);
_UIMessageQueueMutex.unlock();
}