Cocos2d-x中使用Socket方法总结

From: http://blog.csdn.net/u010105970/article/details/41511973

Socket又称"套接字",用于向网络发出请求或者应答网络请求

Socket工作的示意图:

程序实例:在Cocos2d-X中使用Socket

创建一个Sock类,用于处理Socket

在Sock.h中添加下面的代码

  1. #ifndef __Sock_H__   
  2. #define __Sock_H__   
  3.   
  4. #ifdef WIN32   
  5. #include <WinSock2.h>   
  6. #define SOCK_TYPE SOCKET   
  7. #else   
  8. #define SOCK_TYPE int   
  9. #define INVALID_SOCKET -1   
  10. #endif   
  11.   
  12. #define MyLog(...)    
  13.   
  14. //创建Sock类   
  15. class Sock  
  16. {  
  17. public:  
  18.     //构造函数   
  19.     Sock();  
  20.   
  21.     //析构函数   
  22.     virtual ~Sock();  
  23.   
  24.     //设置成非阻塞模式   
  25.     bool setNonBlock()  
  26.     {  
  27.         SOCK_TYPE fd = _fd;  
  28.   
  29. #ifdef WIN32   
  30.         BOOL flg = TRUE;  
  31.   
  32.         //控制Socket的模式   
  33.         if(ioctlsocket(fd, FIONBIO, (unsigned long *)&flg) != 0)  
  34.         {  
  35.             return false;  
  36.         }  
  37.   
  38.         return true;  
  39.   
  40. #else   
  41.         int flags = fcntl(fd, F_GETFL, 0);  
  42.         flags |= O_NONBLOCK;  
  43.         return fcntl(fd, F_SETFL, flags) != -1;  
  44. #endif   
  45.     }  
  46.   
  47.     //关闭Sock   
  48.     void close()  
  49.     {  
  50. #ifdef WIN32   
  51.         closesocket(_fd);  
  52. #else   
  53.         ::close(_fd);  
  54. #endif   
  55.     }  
  56.   
  57.     void attach(SOCK_TYPE fd)  
  58.     {  
  59.         _fd = fd;   
  60.     }  
  61.   
  62.     //判断Sock是否合法   
  63.     bool isValidSocket()  
  64.     {  
  65.         return _fd != INVALID_SOCKET;   
  66.     }  
  67.   
  68. protected:  
  69.       
  70.     SOCK_TYPE _fd;  
  71. };  
  72.   
  73.   
  74. //客户端的Sock   
  75. class SockClient : public Sock  
  76. {  
  77. public:  
  78.     //构造函数   
  79.     SockClient(unsigned short port = 0, const char* ip = NULL)  
  80.     {  
  81.         if (port == 0 && ip == NULL)  
  82.         {  
  83.             return;  
  84.         }  
  85.   
  86.         //连接   
  87.         connect(port, ip);  
  88.     }  
  89.   
  90.     //析构函数   
  91.     ~SockClient(){}  
  92.   
  93.       
  94.     //连接   
  95.     //第一个参数:端口   
  96.    //第二个参数:ip地址   
  97.     int connect(unsigned short port, const char* ip)  
  98.     {  
  99.         //分配一个Socket   
  100.         //第一个参数:AF_INET表示指定地址族(地址描述)   
  101.         //第二个参数:SOCK_STREAM表示流式套接字TCP(Socket类型)   
  102.         //第三个参数:0(协议)   
  103.         _fd = socket(AF_INET, SOCK_STREAM, 0);  
  104.   
  105.         //地址信息结构   
  106.         struct sockaddr_in addr;  
  107.           
  108.         //地址家族   
  109.         addr.sin_family = AF_INET;  
  110.   
  111.         //端口号   
  112.         addr.sin_port = htons(port);  
  113.   
  114.         //主机地址   
  115.         addr.sin_addr.s_addr = inet_addr(ip);  
  116.   
  117.         //连接   
  118.         int ret = ::connect(_fd, (struct sockaddr*)&addr, sizeof(addr));  
  119.           
  120.         if (ret < 0)  
  121.         {  
  122.             MyLog("connect error errno=%d", errno);  
  123.             return -1;  
  124.         }  
  125.   
  126.         return 0;  
  127.     }  
  128.   
  129.     //接收   
  130.     int recv(char* buf, int len)  
  131.     {  
  132.         return ::recv(_fd, buf, len, 0);  
  133.     }  
  134.   
  135.     //发送   
  136.     int send(const char* buf, int len)  
  137.     {  
  138.         return ::send(_fd, buf, len, 0);  
  139.     }  
  140. };  
  141.   
  142. //服务器端的Sock   
  143. class SockServer :public Sock  
  144. {  
  145. public:  
  146.     //构造函数   
  147.     SockServer(unsigned short port, const char* ip = NULL)  
  148.     {  
  149.         //监听   
  150.         listen(port, ip);  
  151.     }  
  152.   
  153.     //虚构函数   
  154.     ~SockServer(){}  
  155.   
  156.     //接受连接   
  157.     SockClient* accept()  
  158.     {  
  159.         //接受客户端的发送请求,等待客户端发送connect请求   
  160.         SOCK_TYPE fd = ::accept(_fd, NULL, NULL);  
  161.           
  162.         if (fd != INVALID_SOCKET)  
  163.         {  
  164.             //创建一个SockClient   
  165.             SockClient* ret = new SockClient;  
  166.             ret->attach(fd);  
  167.             return ret;  
  168.         }  
  169.         return NULL;  
  170.     }  
  171.   
  172. protected:  
  173.     //监听   
  174.     //第一个参数:端口   
  175.     //第二个参数:ip地址   
  176.     int listen(unsigned short port, const char* ip = NULL)  
  177.     {  
  178.           //分配一个Socket   
  179.         //第一个参数:AF_INET表示指定地址族(地址描述)   
  180.         //第二个参数:SOCK_STREAM表示流式套接字TCP(Socket类型)   
  181.         //第三个参数:0(协议)   
  182.         _fd = socket(AF_INET, SOCK_STREAM, 0);  
  183.   
  184.         //地址信息结果   
  185.         struct sockaddr_in addr;  
  186.   
  187.         //地址家族   
  188.         addr.sin_family = AF_INET;  
  189.   
  190.         //端口号   
  191.         addr.sin_port = htons(port);  
  192.           
  193.         if (ip == NULL)  
  194.         {  
  195.             //设置一个不确定的ip地址   
  196.             addr.sin_addr.s_addr = INADDR_ANY;  
  197.         }  
  198.         else  
  199.         {  
  200.             //将ip地址转换为32位二进制网络字节序的IPV4地址   
  201.             addr.sin_addr.s_addr = inet_addr(ip);  
  202.         }  
  203.   
  204.         //绑定   
  205.         int ret = bind(_fd, (struct sockaddr*)&addr, sizeof(addr));  
  206.           
  207.         if (ret < 0)  
  208.         {  
  209.             MyLog("bind error");  
  210.             return -1;  
  211.         }  
  212.   
  213.         //设置成非阻塞   
  214.         this->setNonBlock();  
  215.   
  216.         //监听   
  217.         ::listen(_fd, 10);  
  218.   
  219.         return 0;  
  220.     }  
  221. };  
  222.   
  223. #endif  
#ifndef __Sock_H__
#define __Sock_H__

#ifdef WIN32
#include <WinSock2.h>
#define SOCK_TYPE SOCKET
#else
#define SOCK_TYPE int
#define INVALID_SOCKET -1
#endif

#define MyLog(...) 

//创建Sock类
class Sock
{
public:
    //构造函数
	Sock();

    //析构函数
	virtual ~Sock();

    //设置成非阻塞模式
	bool setNonBlock()
	{
		SOCK_TYPE fd = _fd;

#ifdef WIN32
		BOOL flg = TRUE;

        //控制Socket的模式
        if(ioctlsocket(fd, FIONBIO, (unsigned long *)&flg) != 0)
        {
            return false;
        }

		return true;

#else
		int flags = fcntl(fd, F_GETFL, 0);
		flags |= O_NONBLOCK;
		return fcntl(fd, F_SETFL, flags) != -1;
#endif
	}

    //关闭Sock
	void close()
	{
#ifdef WIN32
		closesocket(_fd);
#else
		::close(_fd);
#endif
	}

	void attach(SOCK_TYPE fd)
    {
        _fd = fd; 
    }

    //判断Sock是否合法
	bool isValidSocket()
    {
        return _fd != INVALID_SOCKET; 
    }

protected:
	
	SOCK_TYPE _fd;
};


//客户端的Sock
class SockClient : public Sock
{
public:
    //构造函数
	SockClient(unsigned short port = 0, const char* ip = NULL)
    {
		if (port == 0 && ip == NULL)
        {
			return;
        }

        //连接
		connect(port, ip);
	}

    //析构函数
	~SockClient(){}

    
    //连接
    //第一个参数:端口
   //第二个参数:ip地址
	int connect(unsigned short port, const char* ip)
	{
        //分配一个Socket
        //第一个参数:AF_INET表示指定地址族(地址描述)
        //第二个参数:SOCK_STREAM表示流式套接字TCP(Socket类型)
        //第三个参数:0(协议)
		_fd = socket(AF_INET, SOCK_STREAM, 0);

        //地址信息结构
		struct sockaddr_in addr;
		
        //地址家族
        addr.sin_family = AF_INET;

        //端口号
		addr.sin_port = htons(port);

        //主机地址
		addr.sin_addr.s_addr = inet_addr(ip);

        //连接
		int ret = ::connect(_fd, (struct sockaddr*)&addr, sizeof(addr));
		
        if (ret < 0)
		{
			MyLog("connect error errno=%d", errno);
			return -1;
		}

		return 0;
	}

    //接收
	int recv(char* buf, int len)
	{
		return ::recv(_fd, buf, len, 0);
	}

    //发送
	int send(const char* buf, int len)
	{
		return ::send(_fd, buf, len, 0);
	}
};

//服务器端的Sock
class SockServer :public Sock
{
public:
    //构造函数
	SockServer(unsigned short port, const char* ip = NULL)
    {
        //监听
		listen(port, ip);
	}

    //虚构函数
	~SockServer(){}

    //接受连接
	SockClient* accept()
	{
        //接受客户端的发送请求,等待客户端发送connect请求
		SOCK_TYPE fd = ::accept(_fd, NULL, NULL);
		
        if (fd != INVALID_SOCKET)
		{
            //创建一个SockClient
			SockClient* ret = new SockClient;
			ret->attach(fd);
			return ret;
		}
		return NULL;
	}

protected:
	//监听
    //第一个参数:端口
    //第二个参数:ip地址
	int listen(unsigned short port, const char* ip = NULL)
	{
          //分配一个Socket
        //第一个参数:AF_INET表示指定地址族(地址描述)
        //第二个参数:SOCK_STREAM表示流式套接字TCP(Socket类型)
        //第三个参数:0(协议)
		_fd = socket(AF_INET, SOCK_STREAM, 0);

        //地址信息结果
		struct sockaddr_in addr;

        //地址家族
		addr.sin_family = AF_INET;

        //端口号
		addr.sin_port = htons(port);
		
        if (ip == NULL)
        {
            //设置一个不确定的ip地址
            addr.sin_addr.s_addr = INADDR_ANY;
        }
		else
        {
            //将ip地址转换为32位二进制网络字节序的IPV4地址
            addr.sin_addr.s_addr = inet_addr(ip);
        }

        //绑定
		int ret = bind(_fd, (struct sockaddr*)&addr, sizeof(addr));
		
        if (ret < 0)
		{
			MyLog("bind error");
			return -1;
		}

        //设置成非阻塞
		this->setNonBlock();

        //监听
		::listen(_fd, 10);

		return 0;
	}
};

#endif

在Sock.cpp中添加下面的代码

  1. #include "Sock.h"   
  2.   
  3. //构造函数   
  4. Sock::Sock() :_fd(INVALID_SOCKET)  
  5. {  
  6.   
  7. #ifdef WIN32   
  8.       
  9.     //初始化Windoes下的Sock   
  10.     static bool winInit = false;  
  11.     if (!winInit)  
  12.     {  
  13.         winInit = true;  
  14.   
  15.         WSADATA data;  
  16.         WSAStartup(MAKEWORD(2, 2), &data);  
  17.     }  
  18. #endif   
  19. }  
  20.   
  21.   
  22. //虚构函数   
  23. Sock::~Sock()  
  24. {  
  25.     if (isValidSocket())  
  26.     {  
  27.         close();  
  28.     }  
  29. }  
#include "Sock.h"

//构造函数
Sock::Sock() :_fd(INVALID_SOCKET)
{

#ifdef WIN32
	
    //初始化Windoes下的Sock
    static bool winInit = false;
    if (!winInit)
	{
		winInit = true;

		WSADATA data;
		WSAStartup(MAKEWORD(2, 2), &data);
	}
#endif
}


//虚构函数
Sock::~Sock()
{
	if (isValidSocket())
	{
		close();
	}
}


再创建一个SocketTest类,用于测试Socket

在SocketTest.h中添加下面的代码

  1. #ifndef __SocketTest_H__   
  2. #define __SocketTest_H__   
  3.   
  4. #include "cocos2d.h"   
  5. #include"Sock.h"   
  6. USING_NS_CC;  
  7.   
  8.   
  9.   
  10. class SocketTest : public CCLayer   
  11. {  
  12. public:  
  13.     static CCScene* scene();  
  14.   
  15.     CREATE_FUNC(SocketTest);  
  16.     bool init();  
  17.   
  18.     SockServer* _server;  
  19.     SockClient* _client;  
  20.   
  21.     //启动服务器   
  22.     void makeServer(CCObject*);  
  23.   
  24.     //启动客服端   
  25.     void makeClient(CCObject*);  
  26.   
  27.     //接受连接   
  28.     void Accept(CCObject*);  
  29.   
  30.     //发送   
  31.     void Send(CCObject*);  
  32.   
  33.     //接收   
  34.     void Recv(CCObject*);  
  35.   
  36. };  
  37.   
  38. #endif  
#ifndef __SocketTest_H__
#define __SocketTest_H__

#include "cocos2d.h"
#include"Sock.h"
USING_NS_CC;



class SocketTest : public CCLayer 
{
public:
	static CCScene* scene();

	CREATE_FUNC(SocketTest);
	bool init();

    SockServer* _server;
    SockClient* _client;

    //启动服务器
    void makeServer(CCObject*);

    //启动客服端
    void makeClient(CCObject*);

    //接受连接
    void Accept(CCObject*);

    //发送
    void Send(CCObject*);

    //接收
    void Recv(CCObject*);

};

#endif

在SocketTest.cpp中添加下面的代码

  1. #include "SocketTest.h"   
  2.   
  3.   
  4. CCScene* SocketTest::scene()  
  5. {  
  6.     CCScene* s = CCScene::create();  
  7.     SocketTest* layer = SocketTest::create();  
  8.     s->addChild(layer);  
  9.     return s;  
  10. }  
  11.   
  12.   
  13. bool SocketTest::init()  
  14. {  
  15.     CCLayer::init();  
  16.   
  17.     CCMenuItemFont* item1 = CCMenuItemFont::create("MakeServer"this, menu_selector(SocketTest::makeServer));  
  18.     CCMenuItemFont* item2 = CCMenuItemFont::create("MakeClient"this, menu_selector(SocketTest::makeClient));  
  19.     CCMenuItemFont* item3 = CCMenuItemFont::create("Send"this, menu_selector(SocketTest::Send));  
  20.     CCMenuItemFont* item4 = CCMenuItemFont::create("Recv"this, menu_selector(SocketTest::Recv));  
  21.     CCMenuItemFont* item5 = CCMenuItemFont::create("Accept"this, menu_selector(SocketTest::Accept));  
  22.     CCMenu* menu = CCMenu::create(item1, item2, item3, item4, item5, NULL);  
  23.     addChild(menu);  
  24.     menu->alignItemsVertically();  
  25.       
  26.     return true;  
  27. }  
  28.   
  29.   
  30. //启动服务器   
  31. void SocketTest::makeServer(CCObject*)  
  32. {  
  33.     this->_server = new SockServer(9888);  
  34.       
  35.     if (!this->_server->isValidSocket())  
  36.     {  
  37.         CCLog("server ERR");  
  38.     }  
  39.     else  
  40.     {  
  41.         CCLog("server OK");  
  42.     }  
  43. }  
  44.   
  45.   
  46. //启动客服端   
  47. void SocketTest::makeClient(CCObject*)  
  48. {  
  49.     this->_client = new SockClient(9888, "127.0.0.1");  
  50.       
  51.     if (!this->_client->isValidSocket())  
  52.     {  
  53.         CCLog("Client ERR");  
  54.     }  
  55.     else  
  56.     {  
  57.         CCLog("Client OK");  
  58.     }  
  59. }  
  60.   
  61.   
  62. //接受连接   
  63. void SocketTest::Accept(CCObject*)  
  64. {  
  65.     this->_client = this->_server->accept();  
  66.       
  67.     if (!this->_client->isValidSocket())  
  68.     {  
  69.         CCLog("Accept ERR");  
  70.     }  
  71.     else  
  72.     {  
  73.         CCLog("Accept OK");  
  74.     }  
  75. }  
  76.   
  77.   
  78. //发送   
  79. void SocketTest::Send(CCObject*)  
  80. {  
  81.     //发送信息   
  82.     int ret = this->_client->send("Hello", 6);  
  83.     CCLog("send: ret is %d", ret);  
  84. }  
  85.   
  86.   
  87. //接收   
  88. void SocketTest::Recv(CCObject*)  
  89. {  
  90.     char buf[128];  
  91.   
  92.     //接收信息   
  93.     int ret = this->_client->recv(buf, sizeof(buf));  
  94.     CCLog("recv buf is %s", buf);  
  95. }  
#include "SocketTest.h"


CCScene* SocketTest::scene()
{
	CCScene* s = CCScene::create();
	SocketTest* layer = SocketTest::create();
	s->addChild(layer);
	return s;
}


bool SocketTest::init()
{
	CCLayer::init();

    CCMenuItemFont* item1 = CCMenuItemFont::create("MakeServer", this, menu_selector(SocketTest::makeServer));
	CCMenuItemFont* item2 = CCMenuItemFont::create("MakeClient", this, menu_selector(SocketTest::makeClient));
	CCMenuItemFont* item3 = CCMenuItemFont::create("Send", this, menu_selector(SocketTest::Send));
	CCMenuItemFont* item4 = CCMenuItemFont::create("Recv", this, menu_selector(SocketTest::Recv));
	CCMenuItemFont* item5 = CCMenuItemFont::create("Accept", this, menu_selector(SocketTest::Accept));
	CCMenu* menu = CCMenu::create(item1, item2, item3, item4, item5, NULL);
	addChild(menu);
	menu->alignItemsVertically();
	
    return true;
}


//启动服务器
void SocketTest::makeServer(CCObject*)
{
	this->_server = new SockServer(9888);
	
    if (!this->_server->isValidSocket())
	{
		CCLog("server ERR");
	}
	else
	{
		CCLog("server OK");
	}
}


//启动客服端
void SocketTest::makeClient(CCObject*)
{
	this->_client = new SockClient(9888, "127.0.0.1");
	
    if (!this->_client->isValidSocket())
	{
		CCLog("Client ERR");
	}
	else
	{
		CCLog("Client OK");
	}
}


//接受连接
void SocketTest::Accept(CCObject*)
{
	this->_client = this->_server->accept();
	
    if (!this->_client->isValidSocket())
	{
		CCLog("Accept ERR");
	}
	else
	{
		CCLog("Accept OK");
	}
}


//发送
void SocketTest::Send(CCObject*)
{
    //发送信息
	int ret = this->_client->send("Hello", 6);
	CCLog("send: ret is %d", ret);
}


//接收
void SocketTest::Recv(CCObject*)
{
	char buf[128];

    //接收信息
	int ret = this->_client->recv(buf, sizeof(buf));
	CCLog("recv buf is %s", buf);
}

执行结果:


测试SocketTest:

启动两个SocketTest程序,一个做服务器一个做客户端

服务器上单击makeServer,启动服务器

打印Server Ok表示服务器启动成功

                                                                               


客户端单击makeClient,启动客户端



服务器上单击Accept,连接客户端

打印Accept Ok表示接受连接


客户端单击Send,客户端发送消息到服务器


服务器上单击Recv,接收服务器上发来的消息

打印出了"recv buf is Hello"表示服务器上收到了客户端发送的消息


服务器上单击Send,服务器发送消息到客户端

打印出了“send: ret is 6”表示服务器成功的向客户端发送了一个消息



客服端上单击Recv,客户端接收服务器发来的消息



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值