Protocol Buffer是Google所提供的一種結構化資料的編碼方式,俱備高效的序列化速度且支援格式擴充。以Flash來說就是類似AMF的資料傳輸格式,由於Protocol Buffer有支援多種語言版本,這次就來介紹Flash版的Protocol Buffer。
請先至http://code.google.com/p/protobuf/下載對應語言的Library,目前官方僅支援C++、Java及Python,如果要使用其它語言,可透過第三方支援外掛 http://code.google.com/p/protobuf/wiki/ThirdPartyAddOns
範例是採用protoc-gen-as3(https://code.google.com/p/protoc-gen-as3/),這是由一位大陸高手寫的Library,有更新到最新版本,支援度較高
下載好Library後,在專案內設置Library路徑,接下來就可以試用Protocol Buffer了。Protocol Buffer是使用proto文件來產生對應類別,簡單來說,文件格式只定義在proto文件,在不同平台,不同語言時只要用讓編譯器執行proto文件就可產出對應語言的類別,且該類別也會封裝序列化及反序列化方法,開發者只要知道該類別的格式即可。
寫一個簡單的程式範例,記一個旗標值,如果登人了就送出登出結果,反之登出就送出登入結果,觀看範例
範例的proto文件格式:
package protobuf; message ResultMessage { extensions 100 to max; } message LoginResult { extend ResultMessage { optional LoginResult loginExt = 100; } required string name = 1; required string data = 2; } message LogoutResult { extend ResultMessage { optional LogoutResult logoutExt = 101; } }
範例的proto記述了LoginResult、LogoutResult 、ResultMessage等傳輸資料格式,比較特殊的是每個欄位後都要加一個Assigning Tag,該Tag在類別定義內不可重覆,這個Tag是Protobufer用來識別資料欄位的,除了Tag外,範例還有使用extend,extend是Prootocol Buffer用來擴充資料用,該用途會在之後的文章提到。定義好的文件可用Protoc編譯器產生實體類別:
protoc --as3_out=輸出位置 --plugin=AS3 Plugin位置 -I=檔案根位置 descriptor.proto路徑
也可使用Ant來執行:
<project name="protocol buffer" default="protoc"> <target name="protoc"> <exec executable="${basedir}/compiler/protoc"> <arg line="-I=${basedir}/src" /> <arg line="--plugin=protoc-gen-as3=${basedir}/compiler/protoc-gen-as3.bat"/> <arg value="--as3_out=${basedir}/src" /> <arg value="${basedir}/src/test.proto" /> </exec> </target> </project>
執行完後protobuf資料夾下會產生LoginResult、LogoutResult 等類別,透過此類別我們可以寫入及讀取ProtocolBuffer資料,先示範一下如何寫入
private function writeResult():ByteArray { var resultWrapper:ResultMessage = new ResultMessage(); if (!isLogin) { var loginResult:LoginResult = new LoginResult(); loginResult.name = "test"; loginResult.data = "success"; resultWrapper[LoginResult.loginExt] = loginResult; } else { resultWrapper[LogoutResult.logoutExt] = new LogoutResult(); } var resultStream:ByteArray = new ByteArray(); resultWrapper.writeExternal(resultStream); return resultStream; }
上面程式展示Flash物件轉成Protocol Buffer資料,使用的Flash物件是由Protoc編譯產生,繼承Message類,該類別實作序列化及反序列化方法,只要使用writeExternal()即可寫成Protobuffer資料,其格式為ByteArray。
而要讀取時,只需調用readExternal
private function readResult(stream:ByteArray):void { stream.position = 0; var result:ResultMessage = new ResultMessage(); result.readExternal(stream); for (var key:* in result) { var id:uint = key; resultHandler(id, result[key]); } } private function resultHandler(id:uint, data:Message):void { switch (id) { case LoginResult.loginExt: { println("login success"); println("data = " + LoginResult(data).toString()); isLogin = true; break; } case LogoutResult.logoutExt: { println("logout"); isLogin = false; break; } } }
資料的反解一樣可使用物件的反序列化方法,調用Message的readExternal()可把Protocol Buffer資料轉成Flash物件,但一種物件只能轉一種格式,所以以資料傳輸來說是很不方便,Google會提供二種做法來解決這個問題,一種是使用Wrapper類,在Wrapper中加入類型及所有可能傳遞的資料欄位,程式可依類型來判斷所取得的資料,而另一種做法就是使用extend,extend像是類別的額外資料,以列表方式附屬在類別之中,程式可以在列表中找出想要的資料,以使用上來說,extend在擴充資料上比Wrapper容易,所以範例是使用extend的方式來反解回傳資料。
備註:本地讀取ByteArray資料時記得要把位置還原到0,否則無法正常讀取
ProtocolBuffer的基本操作介紹的差不多了,雖然使用上很簡單,但還是比AMF稍嫌難用,下一篇我再來比較兩者格式的差異,包括效能及大小。
參考文件:
protocolBuffer:http://code.google.com/p/protobuf/
protoc-gen-as3:https://code.google.com/p/protoc-gen-as3/
Union Type:http://code.google.com/apis/protocolbuffers/docs/techniques.html#union
寫的很辛苦,如果要轉載請註明出處,謝謝
期待您的性能测试
Atry
2011年5月26日 下午2:14