標籤:lis class bsp tty 關係 hls require file lua
cocos2d-x lua 中使用protobuf並對http進行處理
本文介紹 cocos2d-x lua 中使用http 和 基於cocos2d-x 對lua http的封裝(部分ok)
本部落格連結
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 *.protodo#echo $i#echo ${i%.*}".pb"#echo ${i%.*}#pbn = $i | cut -d.pbname=${i%.*}".pb"#echo $pbn#echo $pbnameprotoc --descriptor_set_out $pbname $idoneecho "finish"
也能夠用命令列手動產生
protoc --descriptor_set_out aaa.pb aaa.proto
3)本步驟能夠忽略了,能夠直接用io進行讀取(Android是路徑問題請看本文最以下解釋)在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)本步驟能夠忽略了。能夠直接用io進行讀取(Android是路徑問題請看本文最以下解釋) 上一步完畢後我們要對提到的CCFileUtils.cpp中的類進行改動 假設不改動讀檔案pb檔案會時好時壞 原因是 讀檔案的時候結束總是加入多餘位元組我也不清楚這個問題 進行改動cocos2d-x中CCFileUtils.cpp的以下方法中的讀取資料後處理並在tolua++ 中加入以下方法綁定到lua層
改動CCFileUtils.cp getFileData(const char* pszFileName, const char* pszMode,unsignedlong * pSize)方法(在最後加入\0。保證位元組不多餘)例如以下代碼
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] != ‘\0‘) pBuffer[*pSize] = ‘\0‘; if (! pBuffer) { std::string msg = "Get data from file("; msg.append(pszFileName).append(") failed!"); CCLOG("%s", msg.c_str()); } return pBuffer;}
5)經過上一步驟lua層基本搞定能夠建立本地的資料並encode成資料轉送到server端了 例如以下代碼
local major = { majorId = "795f94a9-3466-41b4-bf16-043ba8081fab" } local buffer = protobuf.encode("com.sj.web.proto.Major", major)6)我們client傳輸資料到server端 server端會返回資料給我們 相同我們接收的資料肯定也是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)上一步中的資料是server端過來的資料。只是在http串連方面遇到了些小插曲
(1)我先前用的是quick-cocos2d-x-lua中封裝的CCHTTPRequest的這個進行server端互動 只是不如願 由於server端過來的資料中是protobuf進行處理過的資料 在進行調試跟蹤後發現過來的資料中不定什麼地方都有\0結束符 這個導致直接在lua中調研CCHTTPRequest中的擷取string 方法資料被截斷不能正常解析 我在CCHTTPRequest::getResponseString進行處理過來的資料處理掉\0 也不行
(2)因為項目中要用的短串連socket我先前已經整合好luasocket。事實上這個開源的socket非常好用 也有對http的支援果斷用這個測試下server端回來的資料 讓我小小喜悅了一下 丟到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層還是不正常。我就進行對\0 進行處理 又讓我喜悅了 處理擷取的server資料例如以下
std::vector<char> *data = response->getResponseData(); std::stringstream mystream; for(int i=0;i<data->size();i++){ //if ((*data)[i] != ‘\0‘) { mystream << (*data)[i]; //}else{ // mystream << ‘\b‘; //} } 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 CCLuaStack.cpp 方法pushCCLuaValue(....) 中 代碼293行代碼。改動例如以下(這樣做能夠直接使用 lua_pushlstring(m_state, stringValue, length) 把全部資料壓到lua上層)
return pushString(value.stringValue().c_str(), value.stringValue().length());
完整方法代碼為:
void CCLuaStack::pushCCLuaValue(const CCLuaValue& value){ const CCLuaValueType type = value.getType(); if (type == CCLuaValueTypeInt) { return pushInt(value.intValue()); } else if (type == CCLuaValueTypeFloat) { return pushFloat(value.floatValue()); } else if (type == CCLuaValueTypeBoolean) { return pushBoolean(value.booleanValue()); } else if (type == CCLuaValueTypeString) { return pushString(value.stringValue().c_str(), value.stringValue().length()); //pushString(value.stringValue().c_str()); } else if (type == CCLuaValueTypeDict) { pushCCLuaValueDict(value.dictValue()); } else if (type == CCLuaValueTypeArray) { pushCCLuaValueArray(value.arrayValue()); } else if (type == CCLuaValueTypeCCObject) { pushCCObject(value.ccobjectValue(), value.getCCObjectTypename().c_str()); }}
好了就介紹到這裡吧希望對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)讀不到檔案
--其它平台local filePath = CCFileUtils:sharedFileUtils():fullPathForFilename("entity/p_result.pb") local addr = io.open(filePath,"rb") protobuffer = addr:read "*a" addr:close() protobuf.register(protobuffer-- android例如以下local filePath = callJava() local addr = io.open(filePath,"rb") protobuffer = addr:read "*a" addr:close() protobuf.register(protobuffer)
近期Google產品及服務全面禁封 表示對國內互連網管控的表示吐槽 可是好的技術成果是無界的(我對protobuf的使用一如既往。如有想用的。請代理去下載吧) 對protobuf的使用總結
1)發現傳輸資料上位元組上特別節省輕量,從這個優勢上傳輸速度明顯快過其它如json,尤其適合遊戲通訊,假設是考慮到使用者通訊流量及頻寬資源節省問題能夠考慮
2)一點不好就是客戶輸出資料不全預計是pbc還原序列化最佳化table對象問題 (和後端互動資料全靠java寫的小client日誌輸出查看,僅僅是為了方便查看後端返回資料) 然後回lua項目進行處理資訊
cocos2d-x lua 中使用protobuf並對http進行處理