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
寫的很辛苦,如果要轉載請註明出處,謝謝
期待您的性能测试
回覆刪除