AMF解析(三)

 

今天我们来继续AMF解析,首先,我们来讲下XML。

XML(readXML):关于AMF中发送XML,都是将XML-DOC转换成字符串来发送。那解析的时候,也就成了解析字符串了。我们将XML的字符串解析出来后,利用W3C标准将字符串转换成XML(具体转换方法自己google下吧)。

 

DATE(readDate):假若一个日期利用AMF二进制表示是{8,1,66,114,-27,-59,-62,-26,80,0},那么我们就将它解析成日期,看下是什么时候。其实一般计算机里的日期也就是相对于1970年1月1日起经过的毫秒数,AMF中会将该毫秒数以double的形式发送,这样我们就简单了,根据前面讲的double解析方式,就可以知道日期了。但,这里,我们要注意点,DATE也会被认为是Object,就跟String,我们要先读取int来判断该日期前面是否已经发送,是第几次发送的。

int a = readInt();

if(a & 1 == 0) //若低位是0,则表示该Date与前面发送的Date是一样的,第a>>1次发送的对象

else //读取double,然后转换成Date。

 

Object(readMyObject):我们先来讲下object类型,因为后面的array与byteArray都要用到Object的读法。下面我们一共讲下两种发送Object与自定义类的两种方式。

1、Object类

   下面是一段as代码:

               var obj:Object = new Object();

               obj.name = "yokia";

               obj.id = 1;

   我们定义上面这样一个对象,拥有name与id两个属性。我们利用byteArray转换成二进制。

   {10,11,1,9,110,97,109,101,6,11,121,111,107,105,97,5,105,100,4,1,1},接下来我们就分析这段二进制是什么意思。

首先,第一个字节10表示Object的类型,这个没什么好讲的。然后我们再按int的读取方式,读取一个int值ref,这个ref包含了很多信息,分为低4位与其余位。此时我们回忆上次讲的string,amf会每次将接受或发送的对象保存到一个列表中,假如再次遇到要发送或接收相同数据,则直接用第X次发送来表示这次的数据。

第1位:若为0,则表示该对象在此次发送的整个数据中已经存在,是在第ref>>1次发送的。

第2位:我们先放下等会讲。

第3位:若为1表示需要自定义序列化方式,利用true或flash来表示,设为externalizable。这个具体什么用,我还没有搞清楚,等下次搞清楚了再补上。

第4位:是否自定义类。若为0则表示发送的数据为自定义对象。否则就是普通的Object,也用true或false,用dynamic来表示。

第4-32位:表示自定义对象中成员变量的个数,用count=ref>>4来表示。

那我们根据上面的规则,来看下ref=11时的情况。11={0000 1011},由于为第一次发送该数据,所以第1位自然是1,表示前面没有发送过。第3位是0,表示利用默认的序列化方式,第4位是1,表示不是自定义对象。如果不是自定义对象,当然也不存在成员变量的说法了,所在成员变量的个数为0。

上面读取一个int后,我们再读取一个string类型的变量,表示as中发送自定义对象与后台对应类的路径,若发送的是普通Object,则该字符为"",即空字符,我们用className来表示。此时我们将上面二进制的第3位1读出来,我们可以知道该字符为空。

那么我们再回头看下,第2位是什么意思,其实这里,我们要把externalizable、dynamic、count和className四个变量组成一个自定义类TraitsInfo,那么第2位就表示这个自定义类前面是否发送过,假如发送过,则直接读取第ref>>2个对象就行了,不需要再根据其余字节来确定。

这里,我们就将这个ref给解析了,一个整型变量包含了这么多信息,真是不容易啊。

接下来,我们根据上面的TraitsInfo来判断,这个是否是自定义类,如果是自定义类,我们再根据count成员变量的个数,循环读取变量名称,即读取string,保存到TraitsInfo对象中。

我们知道了该数据不是自定义类,而是普通Object,则接下来我们读取string,即key值,二进制9,110,97,109,101转变成string后是name,此时我们判断读取到的字符串是否为空,空则表示读取结束。然后我们再读取object,即递归调用readObject的方法,二进制{6,11,121,111,107,105,97}中6表示是字符串类型,其余转换后便是"yokia"字符串了。然后我们一直用同样的方式读取id=1。当我们读取到最后一个字节1时,我们知道字符串为空,则表示读取结束。

通过上面,我们把as发送普通Object类解析完了。接下来,我们来看下自定义类是如何发送的。

 

2、自定义类

    package
        {
             [RemoteClass(alias="com.test.Student")]
              public class student
             {
                  public var id:int;
  
                  public var name:String;
  
                  public function student(id:int,name:String)
                  {
                        this.id = id;
   
                        this.name = name;
                   }

          }
        }

我们定义一个student类,并利用RemoteClass与后台类对应。com.test.Student为后台类的路径。

      var stu:student = new student(1,"yokia");

我们将stu利用AMF转换成二进制后是{10,35,33,99,111,109,46,116,101,115,116,46,83,116,117,100,101,110,116,5,105,100,9,110,97,109,101,4,1,6,11,121,111,107,105,97}

当我们利用上面方法读取ref后,externalizable=false,dynamic=false(即定义类),count=2

然后我们再读取{33,99,111,109,46,116,101,115,116,46,83,116,117,100,101,110,116}为字符串"com.test.Student",便是后台对应类的路径。然后我们根据成员变量的个数,循环调用readString的方法,读取各个成员变量名称,{5,105,100}="id",{9,110,97,109,101}="name"。

完成后,我们再根据成员变量的个数,递归调用readObject的方法,即解析AMF的方法{4,1}=1,{6,11,121,111,107,105,97}="yokia"。

那么上面,我们就将Object给解析完了。

你可能感兴趣的:(其他)