Cocos2d-x与Firefly的通信

来源:互联网 发布:数据库系统原理 pdf 编辑:程序博客网 时间:2024/06/14 04:32
Firefly是一个开源游戏服务器端框架,文档不全,但源码具备一定可读性。对于想用Cocos2d-x与Firefly的程序员来说,官方给的游戏 DiabloWorld 的源码是很重要的参考资源。稍加阅读源码,再结合Firefly论坛里的相关资料,可以推测出一些信息。(Hint - firefly 当前版本 v1.3.3)
  1.  客户端可以使用socket与部署Firefly的服务器通信,socket的实现不依赖于cocos2d-x的库。
  2.  客户端与服务器的通信中的数据要遵守协议规定的格式。

协议

在Firefly框架中,net节点负责管理连接(包括连接建立和连接断开的处理)和数据的接收与发送的处理。firefly.netconnect.protoc模块定义了登陆服务器协议,而客户端与服务器交互的数据格式在firefly.netconnect.datapack模块中声明。基本格式如下:

HEAD_0
HEAD_1
HEAD_2
HEAD_3
protoVersion
serverVersionlengthcommandIddata (消息体)

各个字段的意义在模块中均有说明。在使用Firefly框架的时候,需要使客户端中数据的协议信息与服务器中相关的协议信息一致。在服务器端,可以直接修改firefly.netconnect.datapack中DataPackProtoc的初始值。

客户端代码

在不修改Firefly源码的情况下,默认HEAD_0等字段都是0。DiabloWorld 客户端源码包含了处理通信的代码,抛开多线程与消息队列的设计,可以抽取出简短的可以通信的代码。

bool test() {    int dwServerIP = inet_addr("192.168.1.128");    unsigned short wPort = 1000;    int m_hSocket = -1;    WSADATA wsd;    WSAStartup(MAKEWORD(2,2), &wsd);    m_hSocket = socket(AF_INET, SOCK_STREAM, 0);    if (m_hSocket == -1) {return false;    }    sockaddr_in SocketAddr;    memset(&SocketAddr,0,sizeof(SocketAddr));    SocketAddr.sin_family=AF_INET;    SocketAddr.sin_port=htons(wPort);    SocketAddr.sin_addr.s_addr=dwServerIP;    memset(&(SocketAddr.sin_zero),0,sizeof(SocketAddr.sin_zero));    int iErrorCode = 0;    iErrorCode = connect(m_hSocket,(sockaddr*)&SocketAddr,sizeof(SocketAddr));    if (iErrorCode == -1) {printf("socket connect error:%d\n",errno);return false;    }    Message* msg = new Message("Hello, World", 1);    // send data    int ret = send(m_hSocket, msg->data, 23, 0);    if (ret == -1) {printf("fail to send data\n", errno);    }    return true;}

其中 Message 的定义如下:

class Message {public:    char HEAD_0;    char HEAD_1;    char HEAD_2;    char HEAD_3;    char protoVersion;    byte serverVersion[4];    byte length[4];    byte commandId[4];    // message body    char* data;    Message();    Message(const char* data, int commandId);    int datalength();    ~Message();};
Message::Message():data(NULL) { }Message::Message(const char* data, int commandId) {    HEAD_0 = 1;    HEAD_1 = 0;    HEAD_2 = 0;    HEAD_3 = 0;    protoVersion = 0;    int a = 0;    serverVersion[3] = (byte)(0xff&a);    serverVersion[2]=(byte)((0xff00&a)>>8);    serverVersion[1]=(byte)((0xff0000&a)>>16);    serverVersion[0]=(byte)((0xff000000&a)>>24);    int b=strlen(data)+4;    length[3]=(byte)(0xff&b);    length[2]=(byte)((0xff00&b)>>8);    length[1]=(byte)((0xff0000&b)>>16);    length[0]=(byte)((0xff000000&b)>>24);    int c = commandId;    this->commandId[3]=(byte)(0xff&c);;    this->commandId[2]=(byte)((0xff00&c)>>8);    this->commandId[1]=(byte)((0xff0000&c)>>16);    this->commandId[0]=(byte)((0xff000000&c)>>24);    printf("%d", datalength());    this->data = new char[datalength()];    memcpy(this->data+0,&HEAD_0,1);    memcpy(this->data+1,&HEAD_1,1);    memcpy(this->data+2,&HEAD_2,1);    memcpy(this->data+3,&HEAD_3,1);    memcpy(this->data+4,&protoVersion,1);    memcpy(this->data+5,&serverVersion,4);    memcpy(this->data+9,&length,4);    memcpy(this->data+13,&this->commandId,4);    memcpy(this->data+17,data,strlen(data));}Message::~Message() {    SAFE_DELETE_ARRAY(data);}int Message::datalength() {    return bytesToInt(length) + 13;}

这里bytesToInt方法定义如下:

int bytesToInt(byte* bytes){int addr = bytes[3] & 0xFF;addr |= ((bytes[2] << 8) & 0xFF00);addr |= ((bytes[1] << 16) & 0xFF0000);addr |= ((bytes[0] << 24) & 0xFF000000);return addr;}

以上代码实现客户端连接服务器,并且向服务器发送数据的过程。如果服务器端解析数据失败,那么就会打印"illegal data package --"的字样。





0 0