• 热门专题

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

作者:  发布日期:2014-04-25 20:12:55
  • cocos2d-x lua 中使用protobuf并对http进行处理

    本博客链接

    http://blog.csdn.net/vpingchangxin/article/details/24458051

    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文件都加入到项目资源中

    #!/bin/sh
    #pb = "pb"
    for i in *.proto
    do
    	#echo $i
    	#echo ${i%.*}".pb"
    	#echo ${i%.*}
    	#pbn = $i | cut -d.
    	pbname=${i%.*}".pb"
    	#echo $pbn
    	#echo $pbname
    	protoc --descriptor_set_out $pbname $i
    done
    echo "finish"

     

    也可以用命令行手动生成

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

     

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

     

    unsigned char* CCFileUtils::getFileData(const char* pszFileName, const char* pszMode, unsigned long * pSize)
    {
        unsigned char * pBuffer = NULL;
        CCAssert(pszFileName != NULL && pSize != NULL && pszMode != NULL, "Invalid parameters.");
        *pSize = 0;
        do
        {
            // read the file from hardware
            std::string fullPath = fullPathForFilename(pszFileName);
            FILE *fp = fopen(fullPath.c_str(), pszMode);
            CC_BREAK_IF(!fp);
            
            fseek(fp,0,SEEK_END);
            *pSize = ftell(fp);
            
            fseek(fp,0,SEEK_SET);
            pBuffer = new unsigned char[*pSize];
            *pSize = fread(pBuffer,sizeof(unsigned char), *pSize,fp);
            fclose(fp);
            
        } while (0);
        
        if (*pSize >0 && pBuffer[*pSize] != '')
            pBuffer[*pSize] = '';
        
        if (! pBuffer)
        {
            std::string msg = "Get data from file(";
            msg.append(pszFileName).append(") failed!");
            
            CCLOG("%s", msg.c_str());
        }
        return pBuffer;
    }

     

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

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

     

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

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

        local http = require 'socket.http'
        local ltn12 = require 'ltn12'
        response_body = ""
        request_body = ""
    
        function http.post(u)
            local t = {}
            local r, c, h = http.request{
                url = u,
                method = "POST",
                headers = {
                    ["Content-Type"] = "application/x-protobuf",
                    ["Content-Length"] = #request_body,
                },
                source = ltn12.source.string(request_body),
                sink = ltn12.sink.table(t)}
            return r, c, h, t
        end
    
        -- url = "http://www.baidu.com"
        r,c,h,body=http.post(HTTP_URL)
        print(c)
        if c~= 200 then
            return
        end
        local protobuf = require "protobuf"
        local buffer = CCFileUtils:sharedFileUtils():getFileData("entity/p_result_test.pb","r",0)
        -- print(buffer)
        protobuf.register(buffer)
    
        local t = protobuf.decode("com.sj.web.proto.Result", body[1])
        cclog(t)

    (3)不过我没有用上面中提到的luasocket http 个人感觉还是直接用coco2d-x中的CCHttpClient比较好用也不用处理线程的东西 因为我通过这个测试过c++层中protobuf进行解析是完全没问题的所以我就模仿(1)中提到的CCHTTPRequest对cocos2d::extension::CCHttpClient封装使用不过有点不顺利数据传到lua层还是不正常,我就进行对 进行处理 又让我喜悦了 处理获取的服务器数据如下
    std::vector<char> *data = response->getResponseData();
        std::stringstream mystream;
        for(int i=0;i<data->size();i++){
            if ((*data)[i] != '') {
                mystream << (*data)[i];
            }else{
                mystream << '';
            }
        }
        mResponseData = mystream.str();
        
        std::cout << mystream.str() << std::endl;
        CCLog("ddd:%s",mystream.str().c_str());
        CCString * cstr = CCString::create(temp);
    //    com::sj::web::proto::Result *r = new com::sj::web::proto::Result::Result();
    //    r->ParseFromString(temp.c_str());
    //    CCLog("ParseFromString:::::::::%d  %s",r->resultcode(),r->release_major()->majorcode().c_str());
        CCLuaValueDict dict;
        dict["request"] = CCLuaValue::ccobjectValue(this, "HTTPRequest");
        dict["data"] = CCLuaValue::stringValue(mystream.str()); // 建议不要这样传值回到lua层
        dict["dataCString"] = CCLuaValue::ccobjectValue(cstr, "CCString");
        dict["dddd"] = CCLuaValue::stringValue("dssddsdsds");
        
        LUA_FUNCTION listener = (LUA_FUNCTION)response->getHttpRequest()->getUserData();
        CCLuaStack *stack = CCLuaEngine::defaultEngine()->getLuaStack();
        stack->clean();
        stack->pushCCLuaValueDict(dict);
    
    好了就介绍到这里吧希望对cocos2d-x lua 开发的同行们有所帮助 如果有什么好的protobuf对cocos2d-x lua 的支持 或者是更方便的集成 也请贡献给我一份哟 谢谢

     

延伸阅读:

About IT165 - 广告服务 - 隐私声明 - 版权申明 - 免责条款 - 网站地图 - 网友投稿 - 联系方式
本站内容来自于互联网,仅供用于网络技术学习,学习中请遵循相关法律法规