cocos2dx和skynet通信
来源:互联网 发布:狼群算法求解 编辑:程序博客网 时间:2024/04/25 09:50
最近使用skynet作为服务器开发前端使用cocos2dx-lua。由于前后端都是用lua编写。
在搭建双方的通信环节是有一个步骤就是选择通信的协议。通用选择是protobuf+socket的方式。由于protobuf对lua的支持问题。我们选择了pbc这个proto解析库。
本文解决的问题
前端cocos2dx-lua引擎,使用luasocket+protobuf 和skynet进行通信?
前端使用: luasocket pbc lpack
后端使用: socket pbc string.pack string.unpack
skynet在数据发送时使用的是string.pack() string.unpack() 进行打包解包。然后这两个函数是lua5.3的。前端的cocos是lua5.1没有这个API。
因此才有了lpack这个库。
pbc: https://github.com/cloudwu/pbc.git
lpack: https://github.com/LuaDist/lpack.git
skynet: https://github.com/cloudwu/skynet.git
已经定好协议并且可通信的skynet服务器和cocos2dx客户端:
https://github.com/gameloses/cocos2dx_lua_skynet_client.git
git clone https://github.com/gameloses/skynet_pbc.git
接下来就是进行一个前后端的对接逻辑。
cocos2dx集成pbc和lpack
这是一个已经集成好的cocos2dx的例子,代码开源在github
https://github.com/gameloses/cocos2dx_lua_skynet_client.git
这里例子已经可以可skynet进行通信。 进入这个链接会有u详细的教程。
下面是详细的集成教程。
集成pbc
- 编译pbc
pbc下的src拷贝到编译目录。假设vs。环境下你得建一个pbc目录然后把src下的代码copy到pbc下。编译。
发现pbc的.c在VS中不能按C代码编译,而应该按照C++编译,在所有.c的属性页中的“C/C++ => 高级”中,设置“编译为C++代码”后编译通过。因为pbc全是c代码索引得设置一下。 - 添加luabindings代码
将pbc目录下binding/lua/pbc-lua.c文件copy到项目中。
添加头文件:pbc-lua.h。代码如下:
#ifndef __PBC_LUA_H__#define __PBC_LUA_H__#ifdef __cplusplusextern "C" {#endif#include "lua.h"#include "lualib.h"#include "lauxlib.h"#ifdef __cplusplus}#endif#ifdef __cplusplusextern "C" {#endif int luaopen_protobuf_c(lua_State *L);#ifdef __cplusplus}#endif#endif
编写桥接代码添加到工程:lua_cocos2dx_pbc_manual.h,lua_cocos2dx_pbc_manual.cpp
//lua_cocos2dx_pbc_manual.h#ifndef lua_cocos2dx_pbc_manual_h__#define lua_cocos2dx_pbc_manual_h__#ifdef __cplusplusextern "C" {#endif#include "tolua++.h"#ifdef __cplusplus}#endifTOLUA_API int register_pbc_module(lua_State* L);#endif
//lua_cocos2dx_pbc_manual.cpp#include "lua_bindings/lua_cocos2dx_pbc_manual.h"#include "platform/CCPlatformConfig.h"#include "base/ccConfig.h"#include "scripting/lua-bindings/manual/tolua_fix.h"#include "scripting/lua-bindings/manual/LuaBasicConversions.h"#include "scripting/lua-bindings/manual/CCLuaEngine.h"#include "lua_bindings/pbc-lua.h"#include "cocos/platform/CCFileUtils.h"int read_protobuf_file(lua_State *L){ const char *buff = luaL_checkstring(L, -1); Data data = cocos2d::FileUtils::getInstance()->getDataFromFile(buff); lua_pushlstring(L, (const char*)data.getBytes(), data.getSize()); return 1;}TOLUA_API int register_pbc_module(lua_State* L){ lua_getglobal(L, "_G"); if (lua_istable(L, -1))//stack:...,_G, { lua_register(L, "read_protobuf_file_c", read_protobuf_file); luaopen_protobuf_c(L); } lua_pop(L, 1); return 1;}
- AppDelegate中添加一下代码
#include "lua_bindings/lua_cocos2dx_pbc_manual.h" register_pbc_module(L);
- 编译一下就ok。
android和mac平台比较简单就不说了。 - 将binding/lua 下的 protobuf.lua parser.lua 拷贝到lua代码目录下。
- 测试
添加协议
pbhead.proto
package PbHead;message MsgHead{ required int32 msgtype = 1; required string msgname = 2; required int32 msgret = 3; }
协议生成
protoc --descriptor_set_out proto/pbhead.pb proto/pbhead.proto
解析协议
require "protobuf"local buffer = io.read("proto/pbhead.pb") --读出文件内容protobuf.register(buffer)
编码解码
local msg_head={msgtype = 1, msgname = msg_name, msgret = 0};local pb_head = protobuf.encode("PbHead.MsgHead", msg_head)local data = protobuf.decode("PbHead.MsgHead", pb_head);
集成lpack
- 下载lpack.添加lpack.c到项目中。
- 添加一个lpack.h
#ifndef __LAPCK_H__#define __LAPCK_H__#ifdef __cplusplusextern "C" {#endif#include "lua.h"#include "lualib.h"#include "lauxlib.h"#ifdef __cplusplus}#endif#ifdef __cplusplusextern "C" {#endif int luaopen_pack(lua_State *L);#ifdef __cplusplus}#endif#endif
3.在Appdelegate中添加代码
#include "lpack/lpack.h"luaopen_pack(L);
- 测试
lpack是注册在string类里面的。
string.pack
string.unpack
pack(f,…)
unpack(s,f,[init])
注意unpack多返回了一个长度信息。(坑)
前后端消息格式定义
protocol buffer数据包结构如下:
开头2字节存放一个short数据,表示整个数据包的长度。即:
数据包总长度 = 2 byte + 2 byte + PBMsgHead字节数 + PBMsgBody字节数 + 1 byte
随后的2字节存放一个short数据,表示PBMsgHead数据的长度。
PBMsgBody数据长度 = 数据包总长度 - 2 - 2 - 1 - PBMsgHead数据长度。
需要注意的是 PBMsgBody有可能为空,即没有这个数据。因为错误码放在PBMsgHead里面,当逻辑出错时候,只有错误码,没有PBMsgBody。
luasocket进行数据收发
local LuaSock = class("LuaSock")function LuaSock:connect() local socket = require('luasocket.socket'); self.m_sock = socket.tcp(); self.m_sock:settimeout(0); --非阻塞 self.m_sock:setoption("tcp-nodelay", true) --去掉优化 不用处理粘包 self.m_sock:connect(self.m_ip, self.m_port); --定时检测是否可写以判断socket的状态 self.check_ = schedule(function() if self:connect_is_success() then unschedule(self.check_) end end)endfunction LuaSock:connect_is_success( ... ) local for_write = {}; table.insert(for_write,self.m_sock); local ready_forwrite; _,ready_forwrite,_ = socket.select(nil,for_write,0); if #ready_forwrite > 0 then return true; end return false;endfunction LuaSock:receive() local recvt, sendt, status = socket.select({self.m_sock}, nil, 1) print("input", #recvt, sendt, status) if #recvt <= 0 then return; end local buffer,err = self.m_sock:receive(2); if buffer then --读取二进制数据流 local first, sencond = string.byte(buffer,1,2); local len=first*256+sencond;--通过位计算长度 print("收到数据长度=",len) local buffer,err = self.m_sock:receive(len); --unpack 使用pbc decode local pb_len, pb_head,pb_body,t = string.unpack(buffer, ">PPb"); local msg_head = protobuf.decode("PbHead.MsgHead", pb_head) local msg_body = protobuf.decode(msg_head.msgname, pb_body) print("t:"..t..":"..string.char(t)) endendfunction LuaSock:send() --拼装头 local msg_head={msgtype = 1, msgname = msg_name, msgret = 0}; local pb_head = protobuf.encode("PbHead.MsgHead", msg_head) local pb_body = protobuf.encode(msg_name, msg_body); --计算长度 local pb_head_len=#pb_head; local pb_body_len=#pb_body; local pb_len=2+pb_head_len+2+pb_body_len+1; local data=string.pack(">HPPb",pb_len, pb_head, pb_body, string.byte('t')); --数据发送 local _len ,_error = self.m_sock:send(data); if _len ~= nil and _len == #data then --表示发送成功 endend
至此客户端的工作是完成了。我放在了github上。
skynet 使用pbc
skynet使用pbc解析protobuf,使用socket和客户端通信。
前提是搭建编译skynet的环境。
下载pbc编译make得到protobuf.so
将pbc/binding/lua53/protobuf.lua复制到根目录的lualib目录
protobuf.so文件复制到根目录的luaclib目录。pbc就算是集成好了。
具体的步骤看下面。
服务器编译步骤
clone完整的代码 代码中引用了skynet和pbc
git clone https://github.com/gameloses/skynet_pbc.git
cd skynet_pbc
git submodule init
git submodule update
cd skynet
git submodule init
git submodule update
编译skynet
cd skynet
make linux
编译pbc
cd ../3rd/pbc
make
cd binding
cd lua53
make
如果提示找不到lua.h则需要安装一下lua5.3. make && make install
(或者修改一下Makefile文件,设置lua.h的路径)
将protobuf.lua复制到根目录的lualib目录
protobuf.so文件复制到根目录的luaclib目录
编译proto文件
回到根目录
make
如果没有安装protobuf的话会报错,因为要使用到protoc
yum install protobuf-devel.x86_64
yum install protobuf.x86_64
运行
. run.sh
具体教程见wiki
使用cocos2dx 测试一下连接。
clinet的地址: https://github.com/gameloses/cocos2dx_lua_skynet_client.git
- cocos2dx和skynet通信
- skynet集群及通信
- unity-与skynet通信二三事(sproto,crypt)
- skynet
- Skynet
- skynet
- skynet教程(0)--skynet的获取和编译
- quick-cocos2dx中 lua 和oc的通信
- cocos2dx socket 通信
- cocos2dx socket 通信
- cocos2dx 网络通信 soket
- cocos2dx socket 通信
- cocos2dx socket 通信
- cocos2dx socket 通信
- Skynet 源码学习 -- Socket Server 和 Skynet_socket
- skynet中使用websocket和wss
- cocos2dx 3.x 中 Lua socket 和 node.js 利用scoket互相通信读写二进制数据
- FireFly菜鸟学习二(cocos2dx客户端和服务器通信实现)
- USACO 2.1.4 Healthy Holsteins
- 百度地图返回码161定位成功却getCity是null
- 蓝桥杯 剪格子
- Android开发中自定义string、color、style、drawable,title,布局页面(include)的资源使用方法.txt
- 蓝桥杯 ALGO-1 算法训练 区间k大数查询
- cocos2dx和skynet通信
- Error:The number of method references in a .dex file cannot exceed 64K.
- 腾讯研发工程师及软件测试最新面经!
- java数组排序
- maven的两种打包方式
- 文章标题
- Android 源码编译AIDL 使用实例讲解及Android Studio AIDL的调用详解
- Linux常用命令总结
- ubuntu中enable wifi为灰色的解决办法