FireFly菜鸟学习二(cocos2dx客户端和服务器通信实现)

1.FireFly服务器

FireFly自定义通信协议。
      
#coding:utf8

from firefly.server.globalobject import netserviceHandle
from firefly.server.globalobject import GlobalObject
from firefly.netconnect.datapack import DataPackProtoc

#丢失链接调用
def callWhenConnLost(conn):
	dynamicId = conn.transport.sessionno
	GlobalObject().remote['gate'].callRemote("NetConnLost_2",dynamicId)

def CreatVersionResult(netversion):
    return netversion

def doConnectionMade(conn):
    print '已成功建立一个链接'
    
#返回客户端数据信息
def callbackSingleClientData(_conn, callbackstr):						
	GlobalObject().netfactory.pushObject(2, callbackstr, [_conn.transport.sessionno])


#定义协议信息
dataprotocl = DataPackProtoc(78,37,38,48,9,0)  
GlobalObject().netfactory.setDataProtocl(dataprotocl)  
  
GlobalObject().netfactory.doConnectionLost = callWhenConnLost  
GlobalObject().netfactory.doConnectionMade = doConnectionMade  
  
from firefly.server.globalobject import remoteserviceHandle  
from firefly.server.globalobject import netserviceHandle  


#与客户端通信消息 echo_1 后面的 1 为客户端发送的消息
@netserviceHandle
def echo_1(_conn,data):
    return data
@netserviceHandle
def echo_2(_conn,showtext):
	print showtext
	returnStr = '123'
	return callbackSingleClientData(_conn,returnStr)

    

上面还定义了一个名为echo_1的函数,后面这个_1是Firefly用识别功能函数的ID,绝对不能重复,当我们从客户端发送消息时,如果指定commandId参数为1,则服务端在接收到这个消息时,会执行echo_1这个函数,执行完后的return用来把返回给客户端相应的数据,服务端的代码就算是这样完成了。


2.cocos2dx客户端

了解基本的socket通信。

socket最核心的三个方法就是:

connect() 用于链接服务器

send() 用于发消息到服务器

recv() 用于接收服务器返回的消息

客户端发送的消息格式必须与Firefly的消息格式一致:发送给Firefly服务端的消息中需要包含以下头部信息

在发送的数据之前加上包头。为了做分包的处理。包头中包含了

HEAD_0,------char,字节数 1

HEAD_1,------char,字节数1

HEAD_2,------char,字节数1

HEAD_3,------char,字节数1

ProtoVersion,------char,字节数1

ServerVersion,------int,字节数4

length,-------int,字节数4(command+数据,总长度)

command,------int,字节数4(指令号)

协议头的总长度 17字节

下面就是发送的数据了。然后把协议头和发送的数据拼接发送。官网提供了很多游戏实例源码。
#include "cocos2d.h"
using namespace cocos2d;

typedef signed char byte;

static const unsigned int TYPE_SELF_DEINE_MESSAGE_CONNECT_FAIL = 0xfffffA01;

static const unsigned int TYPE_SELF_DEINE_MESSAGE_CONNECT_TERMINATE = 0xfffffA02;

static const unsigned int TYPE_SELF_DEINE_MESSAGE_SERVER_CLOSE_CONNECTION = 0xfffffA03;

static const unsigned int TYPE_SELF_DEINE_MESSAGE_CANNOT_SEND_MESSAGE = 0xfffffA04;

static const unsigned int TYPE_SELF_DEINE_MESSAGE_IDLE_TIMEOUT = 0xfffffA05;

static const unsigned int TYPE_SELF_DEINE_MESSAGE_RECONNECT_HINT = 0xfffffA06;

static const unsigned int TYPE_SELF_DEINE_MESSAGE_RECONNECT_FORCE = 0xfffffA07;

static const unsigned int TYPE_SELF_DEINE_MESSAGE_ERROR_MESSAGE = 0xfffffA08;

static const unsigned int TYPE_SELF_DEINE_MESSAGE_CLIENT_KILL_MESSAGE = 0xfffffA09;

class Message:public CCObject
{
public:
    
    char HEAD0;
    char HEAD1;
    char HEAD2;
    char HEAD3;
    char ProtoVersion;
    
    byte serverVersion[4];
    byte length[4];
    byte commandId[4];
    
    char* data;
    
    Message();
    int datalength();
    ~Message();
};

再看看消息构造函数,这个也是取自Firefly官方发布的游戏源代码:

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. Message* networkManager::constructMessage(const char* data,int commandId)  
  2. {  
  3.     Message* msg = new Message();  
  4.       
  5.     msg->HEAD0=78;  
  6.     msg->HEAD1=37;  
  7.     msg->HEAD2=38;  
  8.     msg->HEAD3=48;  
  9.     msg->ProtoVersion=9;  
  10.       
  11.     int a=0;  
  12.     msg->serverVersion[3]=(byte)(0xff&a);;  
  13.     msg->serverVersion[2]=(byte)((0xff00&a)>>8);  
  14.     msg->serverVersion[1]=(byte)((0xff0000&a)>>16);  
  15.     msg->serverVersion[0]=(byte)((0xff000000&a)>>24);  
  16.       
  17.     int b=strlen(data)+4;  
  18.       
  19.     msg->length[3]=(byte)(0xff&b);;  
  20.     msg->length[2]=(byte)((0xff00&b)>>8);  
  21.     msg->length[1]=(byte)((0xff0000&b)>>16);  
  22.     msg->length[0]=(byte)((0xff000000&b)>>24);  
  23.       
  24.     int c=commandId;  
  25.     msg->commandId[3]=(byte)(0xff&c);;  
  26.     msg->commandId[2]=(byte)((0xff00&c)>>8);  
  27.     msg->commandId[1]=(byte)((0xff0000&c)>>16);  
  28.     msg->commandId[0]=(byte)((0xff000000&c)>>24);  
  29.       
  30.     //    str.append(msg->HEAD0);  
  31.     printf("%d" ,msg->datalength());  
  32.     msg->data = new char[msg->datalength()];  
  33.     memcpy(msg->data+0,&msg->HEAD0,1);  
  34.     memcpy(msg->data+1,&msg->HEAD1,1);  
  35.     memcpy(msg->data+2,&msg->HEAD2,1);  
  36.     memcpy(msg->data+3,&msg->HEAD3,1);  
  37.     memcpy(msg->data+4,&msg->ProtoVersion,1);  
  38.     memcpy(msg->data+5,&msg->serverVersion,4);  
  39.     memcpy(msg->data+9,&msg->length,4);  
  40.     memcpy(msg->data+13,&msg->commandId,4);  
  41.     memcpy(msg->data+17,data,strlen(data));  
  42.     //memcpy(msg->data+position,bytes+offset,len);  
  43.     //msg->data = data;  
  44.     return msg;  
  45. }  
上面的代码对消息从头到尾按次序进行了一次拼接封装,算是打包进data中,让其成为一个完整的数据包,最后返回消息对象。

然后就是链接服务器了,下面是代码:

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. //连接服务器

    bool networkManager::Connect() {

        mLock.lock();

        if(Init()==-1){

            return false;

        }

        if(Create(AF_INET,SOCK_STREAM,0)==false){

            return false;

        };


        struct sockaddr_in svraddr;

        svraddr.sin_family = AF_INET;

        svraddr.sin_addr.s_addr =inet_addr(IP_ADDRESS);

        svraddr.sin_port = htons(IP_HOST);

        int ret = connect(m_sock, (structsockaddr*) &svraddr, sizeof(svraddr));

        if (ret == SOCKET_ERROR) {

            return false;

        }

        sendThread();

        CCLOG("link successed");

        mLock.unlock();

        return true;

    } 


可以看到上面链接代码的尾部已经加入执行了发送数据的函数,发送的实现代码其实很简单,下面是发送了一条"getSendMessage successful!"的信息给服务器,而如果服务器收到这个消息后,也会在log里输出这样一条消息的:
void networkManager::sendThread(){
    Message* msg=constructMessage("getSendMessage successful!",2);
    Send(msg->data,msg->datalength(),0);
}


发送消息后,则可以开始监听接收服务端返回的数据了,下面只给出了基本代码,不包含数据解析,收到服务端返回的消息后可以看到LOG输出的信息:
//接收数据
void networkManager::RecvFunc(){
    char recvBuf[200];
    FD_ZERO(&fdRead);
    FD_SET(m_sock,&fdRead);
    mLock.lock();
    struct timeval	aTime;
    aTime.tv_sec = 5;
    aTime.tv_usec = 0;
    //Select在Socket编程中还是比较重要的,它能够监视我们需要监视的文件描述符的变化情况——读写或是异常。
    
    int ret = select(m_sock+1,&fdRead,NULL,NULL,&aTime);
    CCLog("socket State=%d",ret);
    if(ret==-1){
        log("socket error");
    }
    if(ret==0){
        printf("selector timeout . continue select.... \n");
    }
    if (ret > 0 )
    {
        if (FD_ISSET(m_sock,&fdRead))
        {
            int getRevDataLength=recv(m_sock,recvBuf,200,0);
            CCLOG("recvThread OK,getDataProcess=%d",getRevDataLength);
            if (getRevDataLength>17) {
                //前17个协议字段相关信息
                for (int i=0; i<17; i++) {
                    log("recv = %d",recvBuf[i]);
                }
                //后面为data信息打印查看
                for (int i=17; i<getRevDataLength; i++) {
                    log("recv = %c",recvBuf[i]);
                }
            }
        }
        
    }
    mLock.unlock();
}

启动服务器客户端完成通信。

原文链接: http://blog.csdn.net/cyistudio/article/details/39805749
相关下载:




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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值