cocos2d-x lua 中使用protobuf并对http进行处理

前端之家收集整理的这篇文章主要介绍了cocos2d-x lua 中使用protobuf并对http进行处理前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

cocos2d-x lua中使用@H_301_2@protobuf并对@H_301_2@http进行处理@H_301_2@

本文介绍 cocos2d-x lua 中使用http 和 基于cocos2d-x 对lua http的封装(部分ok)

博客链接@H_301_2@

http://www.jb51.cc/article/p-uzwmdzfc-qn.html
@H_301_2@

protobuf Google的一个很好用的传输数据的封装 说实话Google的东西确实比较好用 所以我们前后端数据交换就用他了 不过Google没有对lua进行支持 还好社区有开源的大侠们贡献 找了所有关于lua protobuf 我只找到 云风的 pbc 修改相关cocos2d-x中的类可以正常使用。protoc-gen-lua 我在使用的时候 总是报截断数据 在修改后cocs2d-x中的类之后没有对protoc-gen-lua 进行测试是否是这个问题导致

1)集成 云风 云大侠的(博客lua-pbc标准c写的protobuf 具体看pbc的帮助很轻松集成

2) 生成pb文件(我自己写了个mac中批处理生成所有.proto文件为.pb文件)把pb 和proto文件都加入到项目资源中

[objc] view plain copy
  1. #!/bin/sh@H_301_2@@H_301_2@@H_301_2@
  2. #pb="pb"@H_301_2@@H_301_2@@H_301_2@
  3. for@H_301_2@i@H_301_2@in@H_301_2@*@H_301_2@.proto@H_301_2@@H_301_2@@H_301_2@
  4. do@H_301_2@@H_301_2@@H_301_2@
  5. #echo$i@H_301_2@@H_301_2@@H_301_2@
  6. #echo${i%.*}".pb"@H_301_2@@H_301_2@@H_301_2@
  7. #echo${i%.*}@H_301_2@@H_301_2@@H_301_2@
  8. #pbn=$i|cut-d.@H_301_2@@H_301_2@@H_301_2@
  9. pbname=${i%.*}".pb"@H_301_2@@H_301_2@@H_301_2@
  10. #echo$pbn@H_301_2@@H_301_2@@H_301_2@
  11. #echo$pbname@H_301_2@@H_301_2@@H_301_2@
  12. protoc--descriptor_set_out$pbname$i@H_301_2@
  13. done@H_301_2@
  14. echo"finish"@H_301_2@@H_301_2@@H_301_2@

也可以用命令行手动生成

[cpp]
    protoc--descriptor_set_outaaa.pbaaa.proto@H_301_2@@H_301_2@
3)@H_301_2@ 本步骤可以忽略了,可以直接用io进行读取(Android是路径问题请看本文最下面解释)@H_301_2@ 在lua中使用如下代码(我用的是cocos2d-x中绑定的CCFileUtils中的获取文件的方式,不过要手动用tolua++进行绑定到lua,可以参考我上个文章中的绑定方式,云大侠中的 用lua io形式获取在相关了解中不能跨平台所有就用这个了)
[javascript]
@H_502_193@ localprotobuf=require@H_301_2@"protobuf"@H_301_2@@H_301_2@@H_301_2@
  • localbuffer=CCFileUtils:sharedFileUtils():getFileData("entity/p_result.pb"@H_301_2@,@H_301_2@"r"@H_301_2@,0)@H_301_2@@H_301_2@
  • --print(buffer)@H_301_2@
  • protobuf.register(buffer)@H_301_2@
  • 4)@H_301_2@ 本步骤可以忽略了,可以直接用io进行读取(Android是路径问题请看本文最下面解释)@H_301_2@ 上一步完成后我们要对提到的CCFileUtils.cpp中的类进行修改 如果不修改文件pb文件会时好时坏 原因是 读文件的时候结束总是添加多余字节我也不清楚这个问题 进行修改cocos2d-x@H_301_2@中CCFileUtils.cpp@H_301_2@的下面方法中的读取数据后处理并在tolua++ 中添加下面方法绑定到lua层 @H_301_2@

    修改CCFileUtils.cp getFileData(const@H_301_2@char@H_301_2@* pszFileName,const@H_301_2@char@H_301_2@* pszMode,unsigned@H_301_2@long@H_301_2@* pSize)方法(在最后添加\0,保证字节不多余)如下代码

      unsigned@H_301_2@char@H_301_2@*CCFileUtils::getFileData(@H_301_2@const@H_301_2@@H_301_2@char@H_301_2@*pszFileName,@H_301_2@char@H_301_2@*pszMode,unsigned@H_301_2@long@H_301_2@*pSize)@H_301_2@@H_301_2@
    1. {@H_301_2@
    2. unsignedchar@H_301_2@*pBuffer=NULL;@H_301_2@@H_301_2@
    3. CCAssert(pszFileName!=NULL&&pSize!=NULL&&pszMode!=NULL,"Invalidparameters."@H_301_2@);@H_301_2@@H_301_2@
    4. *pSize=0;@H_301_2@
    5. {@H_301_2@
    6. //readthefilefromhardware@H_301_2@@H_301_2@@H_301_2@
    7. std::stringfullPath=fullPathForFilename(pszFileName);@H_301_2@
    8. FILE@H_301_2@*fp=fopen(fullPath.c_str(),pszMode);@H_301_2@@H_301_2@
    9. CC_BREAK_IF(!fp);@H_301_2@
    10. @H_301_2@
    11. fseek(fp,SEEK_END);@H_301_2@
    12. *pSize=ftell(fp);@H_301_2@
    13. @H_301_2@
    14. fseek(fp,SEEK_SET);@H_301_2@
    15. pBuffer=new@H_301_2@unsigned@H_301_2@char@H_301_2@[*pSize];@H_301_2@@H_301_2@
    16. *pSize=fread(pBuffer,sizeof@H_301_2@(unsigned@H_301_2@char@H_301_2@),*pSize,fp);@H_301_2@@H_301_2@
    17. fclose(fp);@H_301_2@
    18. }while@H_301_2@(0);@H_301_2@@H_301_2@
    19. if@H_301_2@(*pSize>0&&pBuffer[*pSize]!=@H_301_2@'\0'@H_301_2@)@H_301_2@@H_301_2@
    20. pBuffer[*pSize]='\0'@H_301_2@;@H_301_2@@H_301_2@
    21. if@H_301_2@(!pBuffer)@H_301_2@@H_301_2@
    22. std::stringmsg="Getdatafromfile("@H_301_2@;@H_301_2@@H_301_2@
    23. msg.append(pszFileName).append(")Failed!"@H_301_2@);@H_301_2@@H_301_2@
    24. CCLOG("%s"@H_301_2@,msg.c_str());@H_301_2@@H_301_2@
    25. }@H_301_2@
    26. return@H_301_2@pBuffer;@H_301_2@@H_301_2@
    27. }@H_301_2@

    5)经过上一步骤lua层基本搞定可以创建本地的数据并encode成传输数据到服务器端了 如下代码

    @H_502_193@ localmajor={@H_301_2@@H_301_2@
  • majorId="795f94a9-3466-41b4-bf16-043ba8081fab"@H_301_2@@H_301_2@@H_301_2@
  • }@H_301_2@
  • localbuffer=protobuf.encode("com.sj.web.proto.Major"@H_301_2@,major)@H_301_2@@H_301_2@
  • 6)我们客户端数据传输到服务器端 服务器端会返回数据给我们 同样我们接收的数据肯定也是protobuf数据了 用 protobuf.decode进行解数据@H_301_2@
    @H_502_193@ localt=protobuf.decode(@H_301_2@"com.sj.web.proto.Result"@H_301_2@,request:getResponseString())--tolua.cast(event.dataCString))--tolua.cast(event.dataCString,@H_301_2@"CCString"@H_301_2@):getCString())@H_301_2@@H_301_2@
  • cclog(t)@H_301_2@
  • print(t.major.gender)@H_301_2@
  • print(t.major.majorId)@H_301_2@
  • print(t.user.username)@H_301_2@
  • 7)上一步中的数据是服务器端过来的数据,不过在http连接方面遇到了些小插曲@H_301_2@

    (1)我先前用的是quick-cocos2d-x-lua中封装的CCHTTPRequest的这个进行服务器端交互 不过不如愿 因为服务器端过来的数据中是protobuf进行处理过的数据 在进行调试跟踪后发现过来的数据中不定什么地方都有\0结束符 这个导致直接在lua中调研CCHTTPRequest中的获取string 方法数据被截断不能正常解析 我在CCHTTPRequest::getResponseString进行处理过来的数据处理掉\0 也不行

    (2)由于项目中要用的短连接socket我先前已经集成好luasocket,其实这个开源的socket很好用 也有对http的支持果断用这个测试下服务器端回来的数据 让我小小喜悦了一下 丢到protobuf.decode中进行解析正是我要的数据 不过有个不好的地方 luasocket对socket有设置一个超时时间 就可以不阻塞线程 但是htpp方式我找遍了网站上的资料也没找到非阻塞式的 不过这个没关系比较可以正常跑protobuf了 集成一个线程框架就ok了呀 可以用协同线程 或者是lua llthreads 自己选择吧如果要用 luasocket的http 先附上luasocket的http代码

    @H_502_193@ localhttp=require@H_301_2@'socket.http'@H_301_2@@H_301_2@@H_301_2@
  • localltn12=require'ltn12'@H_301_2@@H_301_2@@H_301_2@
  • response_body=""@H_301_2@@H_301_2@@H_301_2@
  • request_body=""@H_301_2@@H_301_2@@H_301_2@
  • function@H_301_2@http.post(u)@H_301_2@@H_301_2@
  • localt={}@H_301_2@
  • localr,c,h=http.request{@H_301_2@
  • url=u,@H_301_2@
  • method="POST"@H_301_2@,@H_301_2@@H_301_2@
  • headers={@H_301_2@
  • ["Content-Type"@H_301_2@]=@H_301_2@"application/x-protobuf"@H_301_2@,108); list-style:decimal-leading-zero outside; color:inherit; line-height:18px; margin:0px!important; padding:0px 3px 0px 10px!important"> ["Content-Length"@H_301_2@]=#request_body,@H_301_2@@H_301_2@
  • },@H_301_2@
  • source=ltn12.source.string(request_body),248)"> sink=ltn12.sink.table(t)}@H_301_2@
  • return@H_301_2@r,h,t@H_301_2@@H_301_2@
  • end@H_301_2@
  • --url="http://www.baidu.com"@H_301_2@@H_301_2@@H_301_2@
  • r,body=http.post(HTTP_URL)@H_301_2@
  • print(c)@H_301_2@
  • if@H_301_2@c~=200then@H_301_2@@H_301_2@
  • return@H_301_2@@H_301_2@@H_301_2@
  • end@H_301_2@
  • localprotobuf=require"protobuf"@H_301_2@@H_301_2@@H_301_2@
  • localbuffer=CCFileUtils:sharedFileUtils():getFileData("entity/p_result_test.pb"@H_301_2@,0)@H_301_2@@H_301_2@
  • --print(buffer)@H_301_2@
  • protobuf.register(buffer)@H_301_2@
  • localt=protobuf.decode("com.sj.web.proto.Result"@H_301_2@,body[1])@H_301_2@@H_301_2@
  • cclog(t)@H_301_2@

  • (3)不过我没有用上面中提到的luasocket http 个人感觉还是直接用coco2d-x中的CCHttpClient比较好用也不用处理线程的东西 因为我通过这个测试过c++层中protobuf进行解析是完全没问题的所以我就模仿(1)中提到的CCHTTPRequest对cocos2d@H_301_2@ ::@H_301_2@ extension@H_301_2@ ::@H_301_2@ CCHttpClient封装使用不过有点不顺利数据传到lua层还是不正常,@H_301_2@ 我就进行对\0 进行处理 又让我喜悦了 处理获取的服务器数据如下@H_301_2@
      std::vector<@H_301_2@char@H_301_2@>*data=response->getResponseData();@H_301_2@@H_301_2@
    1. std::stringstreammystream;@H_301_2@
    2. for@H_301_2@(@H_301_2@int@H_301_2@i=0;i<data->size();i++){@H_301_2@@H_301_2@
    3. //if((*data)[i]!='\0'){@H_301_2@@H_301_2@@H_301_2@
    4. mystream<<(*data)[i];@H_301_2@
    5. //}else{@H_301_2@@H_301_2@@H_301_2@
    6. //mystream<<'\b';@H_301_2@@H_301_2@@H_301_2@
    7. //}@H_301_2@@H_301_2@@H_301_2@
    8. mResponseData=mystream.str();@H_301_2@
    9. std::cout<<mystream.str()<<std::endl;@H_301_2@
    10. CCLog("ddd:%s"@H_301_2@,mystream.str().c_str());@H_301_2@@H_301_2@
    11. CCString*cstr=CCString::create(temp);@H_301_2@
    12. //com::sj::web::proto::Result*r=newcom::sj::web::proto::Result::Result();@H_301_2@@H_301_2@@H_301_2@
    13. //r->ParseFromString(temp.c_str());@H_301_2@@H_301_2@@H_301_2@
    14. //CCLog("ParseFromString:::::::::%d%s",r->resultcode(),r->release_major()->majorcode().c_str());@H_301_2@@H_301_2@@H_301_2@
    15. CCLuaValueDictdict;@H_301_2@
    16. dict["request"@H_301_2@]=CCLuaValue::ccobjectValue(@H_301_2@this@H_301_2@,@H_301_2@"HTTPRequest"@H_301_2@);@H_301_2@@H_301_2@
    17. dict["data"@H_301_2@]=CCLuaValue::stringValue(mystream.str());@H_301_2@//传值回到lua层@H_301_2@@H_301_2@@H_301_2@
    18. dict["dataCString"@H_301_2@]=CCLuaValue::ccobjectValue(cstr,@H_301_2@"CCString"@H_301_2@);@H_301_2@@H_301_2@
    19. dict["dddd"@H_301_2@]=CCLuaValue::stringValue(@H_301_2@"dssddsdsds"@H_301_2@);@H_301_2@@H_301_2@
    20. LUA_FUNCTIONlistener=(LUA_FUNCTION)response->getHttpRequest()->getUserData();@H_301_2@
    21. CCLuaStack*stack=CCLuaEngine::defaultEngine()->getLuaStack();@H_301_2@
    22. stack->clean();@H_301_2@
    23. stack->pushCCLuaValueDict(dict);@H_301_2@

    做好上一步进行修改cocos2d-x CCLuaStack.cpp 方法pushCCLuaValue(....) 中 代码293行代码修改如下(这样做可以直接使用lua_pushlstring@H_301_2@(m_state@H_301_2@,stringValue,length) 把所有数据压到lua上层)

      return@H_301_2@pushString(value.stringValue().c_str(),value.stringValue().length());@H_301_2@@H_301_2@

    完整方法代码为:@H_301_2@
      void@H_301_2@CCLuaStack::pushCCLuaValue(@H_301_2@const@H_301_2@CCLuaValue&value)@H_301_2@@H_301_2@
    1. const@H_301_2@CCLuaValueTypetype=value.getType();@H_301_2@@H_301_2@
    2. if@H_301_2@(type==CCLuaValueTypeInt)@H_301_2@@H_301_2@
    3. return@H_301_2@pushInt(value.intValue());@H_301_2@@H_301_2@
    4. else@H_301_2@@H_301_2@if@H_301_2@(type==CCLuaValueTypeFloat)@H_301_2@@H_301_2@
    5. return@H_301_2@pushFloat(value.floatValue());@H_301_2@@H_301_2@
    6. if@H_301_2@(type==CCLuaValueTypeBoolean)@H_301_2@@H_301_2@
    7. return@H_301_2@pushBoolean(value.booleanValue());@H_301_2@@H_301_2@
    8. if@H_301_2@(type==CCLuaValueTypeString)@H_301_2@@H_301_2@
    9. 301_2@//pushString(value.stringValue().c_str());@H_301_2@@H_301_2@@H_301_2@
    10. if@H_301_2@(type==CCLuaValueTypeDict)@H_301_2@@H_301_2@
    11. pushCCLuaValueDict(value.dictValue());@H_301_2@
    12. if@H_301_2@(type==CCLuaValueTypeArray)@H_301_2@@H_301_2@
    13. pushCCLuaValueArray(value.arrayValue());@H_301_2@
    14. if@H_301_2@(type==CCLuaValueTypeCCObject)@H_301_2@@H_301_2@
    15. pushCCObject(value.ccobjectValue(),value.getCCObjectTypename().c_str());@H_301_2@
    16. }@H_301_2@

    好了就介绍到这里吧希望对cocos2d-x lua 开发的同行们有所帮助 如果有什么好的protobuf对cocos2d-x lua的支持 或者是更方便的集成 也请贡献给我一份哟 谢谢

    本人用风云的pbc 心得 总的来说还算可以

    1)浮点类型:java—>lua 没问题;lua—>java 没通过。我们后端用的java 估计是lua对number浮点数类型进行decode的 有整形进行传递的时候导致没有进行对浮点类型转换(或者java对类型比较严格导致解码的时候对高地位转换失败所致) 由于开发效率前后端改成string进行传递(测试过protoc-gen-lua 也有这个问题)如有朋友能使用lua—>java进行浮点类型通信OK 迫切滴希望您共享我一份解决方案@H_301_2@

    2)枚举类型 proto文件中序号从1开始计数 否则pbc pb文件加载失败

    3)上面提到的加载pb文件的时候ios win 也可以根据 CCFileUtils获取pb文件路径后用 lua io进行注册,测试android(我还是用上面提到的方法进行读文件)用这种方式没成功 应该是路径和权限问题导致(已经验证过是android中读取文件路径问题,我的方式是把proto写到本地后lua用io进行读取ok@H_301_2@)读不到文件

    @H_502_193@ --其他平台@H_301_2@@H_301_2@
  • localfilePath=CCFileUtils:sharedFileUtils():fullPathForFilename("entity/p_result.pb"@H_301_2@)@H_301_2@@H_301_2@
  • localaddr=io.open(filePath,"rb"@H_301_2@)@H_301_2@@H_301_2@
  • protobuffer=addr:read"*a"@H_301_2@@H_301_2@@H_301_2@
  • addr:close()@H_301_2@
  • protobuf.register(protobuffer@H_301_2@
  • --android如下@H_301_2@
  • localfilePath=callJava()@H_301_2@
  • protobuf.register(protobuffer)@H_301_2@
  • 最近Google产品及服务全面禁封 表示对国内互联网管控的表示吐槽但是好的技术成果是无界的(我对protobuf的使用一如既往,如有想用的,请代理去下载吧) 对protobuf的使用总结

    1)发现数据传输上字节上特别节省轻量,从这个优势上传输速度明显快过其他如json,尤其适合游戏通信,如果是考虑到用户通信流量及带宽资源节省问题可以考虑

    2)一点不好就是客户输出数据不全估计是pbc反序列化优化table对象问题 (和后端交互数据全靠java写的小客户端日志输出查看,只是为了方便查看后端返回数据) 然后回lua项目进行处理信息


    转载一些自己感觉好的文章,只是为了记录,以后查找方便,大家尽量去阅读原文。@H_301_2@

    原文地址:@H_301_2@http://www.jb51.cc/article/p-uzwmdzfc-qn.html@H_301_2@

    猜你在找的Cocos2d-x相关文章