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

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

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

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

博客链接

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

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
  2. #pb="pb"
  3. foriin*.proto
  4. do
  5. #echo$i
  6. #echo${i%.*}".pb"
  7. #echo${i%.*}
  8. #pbn=$i|cut-d.
  9. pbname=${i%.*}".pb"
  10. #echo$pbn
  11. #echo$pbname
  12. protoc--descriptor_set_out$pbname$i
  13. done
  14. echo"finish"

也可以用命令行手动生成

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

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

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

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

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

(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代码

    localhttp=require'socket.http'
  1. localltn12=require'ltn12'
  2. response_body=""
  3. request_body=""
  4. functionhttp.post(u)
  5. localt={}
  6. localr,c,h=http.request{
  7. url=u,
  8. method="POST",
  9. headers={
  10. ["Content-Type"]="application/x-protobuf",108); list-style:decimal-leading-zero outside; color:inherit; line-height:18px; margin:0px!important; padding:0px 3px 0px 10px!important"> ["Content-Length"]=#request_body,
  11. },
  12. source=ltn12.source.string(request_body),248)"> sink=ltn12.sink.table(t)}
  13. returnr,h,t
  14. end
  15. --url="http://www.baidu.com"
  16. r,body=http.post(HTTP_URL)
  17. print(c)
  18. ifc~=200then
  19. return
  20. end
  21. localprotobuf=require"protobuf"
  22. localbuffer=CCFileUtils:sharedFileUtils():getFileData("entity/p_result_test.pb",0)
  23. --print(buffer)
  24. protobuf.register(buffer)
  25. localt=protobuf.decode("com.sj.web.proto.Result",body[1])
  26. cclog(t)

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

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

    returnpushString(value.stringValue().c_str(),value.stringValue().length());

完整方法代码为:
    voidCCLuaStack::pushCCLuaValue(constCCLuaValue&value)
  1. constCCLuaValueTypetype=value.getType();
  2. if(type==CCLuaValueTypeInt)
  3. returnpushInt(value.intValue());
  4. elseif(type==CCLuaValueTypeFloat)
  5. returnpushFloat(value.floatValue());
  6. if(type==CCLuaValueTypeBoolean)
  7. returnpushBoolean(value.booleanValue());
  8. if(type==CCLuaValueTypeString)
  9. //pushString(value.stringValue().c_str());
  10. if(type==CCLuaValueTypeDict)
  11. pushCCLuaValueDict(value.dictValue());
  12. if(type==CCLuaValueTypeArray)
  13. pushCCLuaValueArray(value.arrayValue());
  14. if(type==CCLuaValueTypeCCObject)
  15. pushCCObject(value.ccobjectValue(),value.getCCObjectTypename().c_str());
  16. }

好了就介绍到这里吧希望对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 迫切滴希望您共享我一份解决方

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

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

    --其他平台
  1. localfilePath=CCFileUtils:sharedFileUtils():fullPathForFilename("entity/p_result.pb")
  2. localaddr=io.open(filePath,"rb")
  3. protobuffer=addr:read"*a"
  4. addr:close()
  5. protobuf.register(protobuffer
  6. --android如下
  7. localfilePath=callJava()
  8. protobuf.register(protobuffer)

最近Google产品及服务全面禁封 表示对国内互联网管控的表示吐槽但是好的技术成果是无界的(我对protobuf的使用一如既往,如有想用的,请代理去下载吧) 对protobuf的使用总结

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

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


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

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

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