Cocos2d-x中使用Socket方法总结

本文详细介绍了如何在Cocos2d-X中使用Socket进行网络编程,包括Socket类的实现、客户端与服务器的建立及通信流程,并通过SocketTest类进行了功能验证。

Borrowed from: http://cn.cocos2d-x.org/tutorial/show?id=2193

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

Socket工作的示意图:

20141126105414969.jpg

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

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

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

#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中添加下面的代码

#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中添加下面的代码

#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中添加下面的代码

#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);
}

执行结果:

1417056090890222.jpg

测试SocketTest:

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

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

1417056163731456.jpg

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

20141126111857953.jpg                                                              

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


20141126112032958.jpg

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

20141126112240640.jpg

打印Accept Ok表示接受连接

20141126112356000.png

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

20141126112438612.jpg

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

20141126112529687.jpg

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

20141126112911359.png

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

20141126112942875.jpg

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

20141126113202136.png

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

20141126113300433.jpg

推荐阅读:

详解Cocos2d-x网络编程


评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值