您的位置:首页 > 移动开发 > Cocos引擎

cocos2d-x socket

2015-12-25 15:55 525 查看
cocos2d-x版本 3.9

纯C++Socket,不用依赖其他库,windows mac iphone android 通用

GameSocket.h

#pragma once
#include "cocos2d.h"
#ifdef _WIN32
#include <windows.h>
#include <WinSock.h>
#pragma comment(lib, "ws2_32.lib")
#else
#include <sys/socket.h>
#include <fcntl.h>
#include <errno.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#define SOCKET int
#define SOCKET_ERROR -1
#define INVALID_SOCKET -1

#endif
#include "TypeDefine.h"
USING_NS_CC;

#define BLOCKSECONDS	30			// INIT函数阻塞时间
#define BUFFER_SIZE (40 * 1024)//可以根据实际情况改大小

class GameSocket
{
public:

GameSocket(void);
bool	Create(const char* pszServerIP, int nServerPort, int nBlockSec = BLOCKSECONDS, bool bKeepAlive = false);
bool	SendMsg(void* pBuf, int nSize);
bool	ReceiveMsg(void* pBuf, int& nSize);
bool	Check(void);
void	Destroy(void);
SOCKET	GetSocket(void) const { return m_sockClient; }
private:
bool	recvFromSock(void);		// 从网络中读取尽可能多的数据
bool    hasError();			// 是否发生错误,注意,异步模式未完成非错误
void    closeSocket();

SOCKET	m_sockClient;

// 发送数据缓冲
char	m_bufOutput[BUFFER_SIZE];	//? 可优化为指针数组
int		m_nOutbufLen;

// 环形缓冲区
char	m_bufInput[BUFFER_SIZE];
int		m_nInbufLen;

};


GameSocket.cpp

<pre name="code" class="cpp">#include "GameSocket.h"

GameSocket::GameSocket()
{
// 初始化
memset(m_bufOutput, 0, sizeof(m_bufOutput));
memset(m_bufInput, 0, sizeof(m_bufInput));
}

void GameSocket::closeSocket()
{
#ifdef WIN32
closesocket(m_sockClient);
WSACleanup();
#else
close(m_sockClient);
#endif
}

bool GameSocket::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)		// or (!FD_ISSET(m_sockClient, &writeset)
{
closeSocket();
return false;
}
}
}
}

m_nInbufLen		= 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 GameSocket::SendMsg(void* pBuf, int nSize)
{
if(pBuf == 0 || nSize <= 0)
{
return false;
}

if (m_sockClient == INVALID_SOCKET)
{
return false;
}
ssize_t outsize = send(m_sockClient, (char*)pBuf, nSize, 0);
if (outsize < 0)
{
if (hasError())
{
Destroy();
return false;
}
}
return true;
}

bool GameSocket::ReceiveMsg(void* pBuf, int& nSize)
{
//检查参数
if(pBuf == NULL || nSize <= 0)
{
return false;
}

if (m_sockClient == INVALID_SOCKET)
{
return false;
}

// 检查是否有一个消息(小于2则无法获取到消息长度)
if(m_nInbufLen < 2)
{
//  如果没有请求成功  或者   如果没有数据则直接返回
if(!recvFromSock() || m_nInbufLen < 2)// 这个m_nInbufLen更新了
{
return false;
}
}

// 检测消息包尺寸错误
if (m_nInbufLen <= 0 || m_nInbufLen > BUFFER_SIZE)
{
m_nInbufLen = 0;		// 直接清空INBUF
return false;
}

// 复制出一个消息
memcpy(pBuf, m_bufInput , m_nInbufLen + sizeof(UINT32));
nSize = m_nInbufLen;

// 重新计算环形缓冲区头部位置
m_nInbufLen = 0;
return	true;
}

bool GameSocket::hasError()
{
#ifdef WIN32
int err = WSAGetLastError();
if (err !=  WSAEWOULDBLOCK)
{
#else
int err = errno;
if(err != EINPROGRESS && err != EAGAIN)
{
#endif
return false;
}

return false;
}

// 从网络中读取尽可能多的数据,实际向服务器请求数据的地方
bool GameSocket::recvFromSock(void)
{
if (m_nInbufLen >= BUFFER_SIZE || m_sockClient == INVALID_SOCKET)
{
return false;
}

// 接收头 我的消息结构是4个字节消息头 存的是消息大小 后面跟的消息体  可以根据实际情况去改
UINT32 nBuffSize = 0;
int inlen = recv(m_sockClient, (char*)&nBuffSize, sizeof(UINT32), 0);
if(inlen > 0)
{
// 有接收到数据
if (inlen > BUFFER_SIZE)
{
return false;
}

//接收消息体
inlen = recv(m_sockClient, m_bufInput, nBuffSize + sizeof(UINT32), 0);
if (inlen > 0)
{
m_nInbufLen = inlen;
if (m_nInbufLen > BUFFER_SIZE)
{
return false;
}
}
else if (inlen == 0)
{
Destroy();
return false;
}
else
{
// 连接已断开或者错误(包括阻塞)
if (hasError())
{
Destroy();
return false;
}
}
}
else if(inlen == 0)
{
Destroy();
return false;
}
else
{
// 连接已断开或者错误(包括阻塞)
if (hasError())
{
Destroy();
return false;
}
}

return true;
}

bool GameSocket::Check(void)
{
// 检查状态
if (m_sockClient == INVALID_SOCKET)
{
return false;
}

char buf[1];
ssize_t	ret = recv(m_sockClient, buf, 1, MSG_PEEK);
if(ret == 0)
{
Destroy();
return false;
}
else if(ret < 0)
{
if (hasError())
{
Destroy();
return false;
}
else
{	// 阻塞
return true;
}
}
else
{	// 有数据
return true;
}

return true;
}

void GameSocket::Destroy(void)
{
// 关闭
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_nOutbufLen = 0;

memset(m_bufOutput, 0, sizeof(m_bufOutput));
memset(m_bufInput, 0, sizeof(m_bufInput));
}






TypeDefine.h

#ifndef WIN32
typedef char        INT8;
typedef short       INT16;
typedef int        INT32;
typedef long long   INT64;
typedef unsigned char       UINT8;
typedef unsigned short      UINT16;
typedef unsigned int       UINT32;
typedef unsigned long long  UINT64;
#endif


用法

1.连接

<pre name="code" class="cpp">GameSocket* m_pSocket = new GameSocket();
bool isCreate = m_pSocket->Create([ip], [port]);
if (!isCreate)
{
CCLOG(" socket connect[%s:%d] fail!", [ip], [port]);
}







2.发消息

bool isSend = m_pSocket->SendMsg([buffer], [buffSize]);
if (!isSend)
{
CCLOG("send world message fail!");
}


3.接收消息

<pre name="code" class="cpp">// 接收消息处理(放到游戏主循环中,每帧处理)
if (m_pSocket == nullptr)
{
return;
}

if (!m_pSocket->Check())
{
m_pSocket = nullptr;
// 掉线了
return;
}

// 接收数据(取得缓冲区中的所有消息,直到缓冲区为空)
while (true)
{
char pbufMsg[BUFFER_SIZE] = { 0 };
int nSize = sizeof(pbufMsg);
if (m_pSocket == nullptr)
{
break;
}
if (!m_pSocket->ReceiveMsg(pbufMsg, nSize))
{
break;
}
//pbufMsg, nSize 这是接收回来的消息内容和大小 根据实际情况进行处理
}






                                            
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: