[教學]在Flash中使用Google Protocol Buffers

protocolBuffer.png

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稍嫌難用,下一篇我再來比較兩者格式的差異,包括效能及大小。

原始檔下載(包含所需Library)

參考文件:

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

寫的很辛苦,如果要轉載請註明出處,謝謝

1 意見 :: [教學]在Flash中使用Google Protocol Buffers

  1. 期待您的性能测试