close

 

啥是AMF

AMF是Action Message Format的簡寫,它是一種二進制的數據格式, 它的設計,是為了把actionscript裡面的數據(包括Object, Array, Boolean, Number等)序列化成一段你基本看不大懂的二進制數據, 然後你可以把這段數據隨意發送給其他地方的程序,比如發給遠程的服務器, 在遠程服務器那邊, 又可以把這段數據給還原出來。以此達到一個數據傳輸的作用。

為什麼要用AMF

通常情況下我們使用JSON或者XML來做數據的傳輸, 他們的好處是文本數據易讀, 容易修改, 壞處在於文本數據體積較大,而且數據的組織有其局限性,比如,你如何在一個JSON /xml裡面表達內含自引用的數據?並且,本人自認為XML和JSON的解析效率並沒有AMF高(。。請高人指正)

為什麼要用AMF

二進制協議的缺點和優點剛好跟JSON/XML反過來。

那麼, 二進制協議是不是只有AMF一個呢。答案明顯是否定的, 你完全可以自定義自己的二進制數據格式,用AMF只是由於它是現成的,拿來即可用,不用重新去發明輪子。當然,現在很多WEB遊戲, 包括不少socialGame,都自己定義過一套二進制的數據格式。(比如人人網上的人人農場)

AMF消息流(AMF Message)

AMF消息流跟AMF不是一回事, AMF消息流就是一個數據包package,它裡麵包含了版本號,頭部,消息體等數據,頭部和消息體裡面用到的數據使用AMF的格式來進行存儲。
AMF數據流常用於NetConnection, SharedObject等

AMF0和AMF3

從官方文檔看,在2001年FLASH PLAYER6中就誕生了AMF0,這是AMF的第一個版本, AMF0的設計比較簡單,直到FLASH8都沒發生過什麼變化。
後來AS3出世,有了新的AVM,於是也就重新設計了一套AMF3,它的基本目的就是讓數據進一步壓縮再壓縮,並且支持了一些新的數據類型比如bytearray等,具體有哪些改動大家自己去看PDF文檔。

那麼AMF3出來之後AMF0是不是可以退休了?答案也是否定的。lol 
大家現在接觸到的AMF3消息流基本上都是在AMF3外麵包了一層AMF0,也就是說我們看到的所有AMF數據流都是AMF0的,
當數據流中的某個數據的type=0 ×11時,才表示這個數據應該屬於AMF3的數據,在這個時候就會切換到AMF3的模式來處理這個數據。處理完之後當然還是繼續回到AMF0的模式處理數據。
大家可以看看這段官方說 明:

NOTE: With the introduction of AMF 3 in Flash Player 9, a special type marker was added to AMF 0 to signal a switch to AMF 3 serialization. This allows NetConnection requests to start out in AMF 0 and switch to AMF 3 on the first complex type to take advantage of the more the efficient encoding of AMF 3.avmplus-object-marker=0×11

例子:一段AMF消息流

下面給大家看一個簡單的例子,下面這個數據是去年我在玩某個國內游戲時截獲的AMF數據流。
16.jpg  

按照AMF0定義的協議,可以如下圖來讀懂這段數據:
21.jpg  

00 03表示版本號為3,其實個人覺得這個版本號用處不大,只是可以提醒你數據流中可能會遇到AMF3的數據00 00表示頭部的個數為0,一般情況下貌似頭部個數都是0,我還沒理解什麼情況下要用到頭部 如果頭部個數為n,那麼接下來應該是n個頭部的數據,這裡因為n=0,所以直接跳過00 01表示消息體的個數為1 接下來就是(消息體的正文=targetURI+responseURI+內容長度+內容)* n,我們這個例子裡n=1targetURI是一個字符串,它表示這個消息要發到哪裡去,在這個例子裡 它= amfService.dispatchAMFresponseURI也是一個字符串,它其實就類似於一個token的作用,因為我們同時可能調用了很多個service,那麼service返回回來的數據要回調哪個處理函數呢? 關鍵就在於這個responseURI,這個字符串會跟著數據流發出去,然後還會回來。 AMF0規定了targetURI和responseURI都是一個UTF字符串,也就是用2個字節來表示字符串長度,後面緊接著字符串正文。 繼續往下看00 16表示targetURI的長度是0×16,61 6D……41 4D 46就是targetURI的值: amfService.dispatchAMF 00 03表示responseURI的長度是3 2F 36 34表示responseURI的值: /64 00 00 00 4D表示後面的內容長度為0×4D 接下來的都是內容正文了,內容正文的數據全是AMF0的的數據 AMF的數據都是一個字節表示type(文檔中稱之為maker),然後緊接著數據0A表示這個是一個標準的Array 00 00 00 02表示數組有2個元素02表示第一個元素的type是字符串,00 30表示第一個元素的字符串的長度是0×30 32 … 33 37表示的是字符串的值00表示第2個元素是一個Number 40 00 00 00 00 00 00 00表示的就是這個Number的值

上面這個例子正好不含有AMF3的數據,說明了開頭的那個版本號3其實並沒有太大意義,我們現在看到的數據都是AMF0的。

第2個例子:AMF3

下面再給大家看一個含有AMF3的例子:
310.jpg  

我們直接切入正文段開始分析00 00 00 1c表示正文段長度是0×1c 11表示數據類型是AMF3,下面切入AMF3的數據流分析0A表示下面是一個AMF3的object對象0B其二進製表示: 0000 1011這裡開始要用二進制來進行分析,秉承了ADOBE一向為求壓縮而摳門到以位而非字節來作為最小存儲單位的優良作風。 這個字節對整個AMF3的Object對像類型進行了關鍵性定義, 先看最右邊一位是1,表示這個object是一個真實的Object,而不是一個reference,(實際上第一次進行存儲的Object都是一個真實的Object,只有第2次使用的時候才是一個reference), 最右邊第2位是一個1,表示了描述這個object的trait數據正緊跟其後,如果是0則也表示該trait數據是一個引用,請到引用緩存池裡面進行尋找吧 最右邊第3位是0,表示了這個object並不是一個Externalizable的實例,簡單來講就是說這個object如果有私有成員,不好意思,這個是不能被序列化到AMF數據裡面的,除非您實現了IExternalizable這個接口。 最後邊第4位是1,表示這個object是一個dynamic對象,你可以隨意往裡面填充或者刪除一些public的動態成員,也就是說緊接著後面我們需要把這個object裡面含有的動態成員給parse出來 最左邊4位0000 ,表示了這個object的靜態member個數是0 接著往下看,下面先緊跟著的是這個object的trait數據了,首先是ClassName,01,其二進制是0000 0001 ,注意01並不是說長度為1,我們先看最右邊一位是1,表示這個ClassName不是一個引用,不需要你到字符串的緩存池裡面去尋找。最左邊是7位,表示這個ClassName的長度正好是0,就是空串”",空串的ClassName就是指這個object的Class就是普通的Object類。 下面就是要讀取一堆dynamic成員的key和value了,一開始並不知道有多少個成員,反正一直讀,直到沒有key為止。key肯定是一個字符串,value類型未知。0D其二進制是0000 1101 ,最右邊是1表示這不是一個reference,剩下的0000 110表示這個key的長度是6,然後後面就是61 75 74 68 6F 72表示的就是這個key的值: author 接著讀value 06表示value的類型是一個字符串07其二進制是000 0111,最右邊是1表示這不是一個reference,剩下的0000 11表示這個key的長度是3,然後後面就是6C 64 78表示value的值是ldx 後面的topic和AMF就不細說了,然後大家看到最後一個字節是01其二進制是0000 0001前面說deserializer並不知道有多少個key,讀到這裡的時候還在試圖讀key,但是發現它不是一個字符串引用,同時它的長度是0000 000=0,那麼表示沒有Key可以讀了,結束

讀取的結果是:

 object : Object = { author: "ldx" , topic: "AMF" 
} ;
arrow
arrow
    全站熱搜

    Y0121 發表在 痞客邦 留言(0) 人氣()