微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

cocos2d-x socket


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,sizeof(m_bufOutput));
    memset(m_bufInput,sizeof(m_bufInput));
}

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

bool GameSocket::Create(const char* pszServerIP,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,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,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,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,sizeof(so_linger));
        
    closeSocket();
        
    m_sockClient = INVALID_SOCKET;
    m_nInbufLen = 0;
    m_nOutbufLen = 0;
        
    memset(m_bufOutput,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 这是接收回来的消息内容和大小 根据实际情况进行处理
	}

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐