使用flex套接字读取AMF对象

时间:2011-05-18 13:02:03

标签: java flex sockets amf

我目前正在尝试使用套接字和AMF序列化对象在java和flex之间进行通信。

在java方面,我使用BlazeDS的Amf3Input和Amf3Output(flex-messaging-common.jar和flex-messaging-core.jar)。

连接已正确建立,如果我尝试将对象从flex发送到java,我可以轻松读取对象:

FLEX方面:

protected function button2_clickHandler(event:MouseEvent):void
{
    var tmp:FlexAck = new FlexAck;
    tmp.id="123456789123456789123456789";
    tmp.name="A";
    tmp.source="Aaaaaa";
    tmp.ackGroup=false;
    s.writeObject(tmp);
    s.flush();
}

JAVA方面:

ServerSocket servSoc = new ServerSocket(8888);
Socket s = servSoc.accept();
Amf3Output amf3Output = new Amf3Output(SerializationContext.getSerializationContext());
amf3Output.setOutputStream(s.getOutputStream());
Amf3Input amf3Input = new Amf3Input(SerializationContext.getSerializationContext());
amf3Input.setInputStream(s.getInputStream());
while(true)
{
    try
    {
      Object obj = amf3Input.readObject();
      if(obj!=null){
          if (obj instanceof AckOrder){
          System.out.println(((AckOrder)obj).getId());
      }
      }                 
}
catch (Exception e)
{
      e.printStackTrace();
  break;
}
  }
  amf3Output.close();
  amf3Input.close();
  servSoc.close();

通过这种方式它可以很好地工作,但问题是要读取从java端发送的对象。

我在java中使用的代码是:

for(int i=0;i<10;i++){
    ack = new AckOrder(i,"A","B", true);
    amf3Output.writeObject(ack);
    amf3Output.writeObjectEnd();
    amf3Output.flush();
}

我在ProgressEvent.SOCKET_DATA上有一个处理程序:

trace((s.readObject()as FlexAck).id);

但我有错误,例如: 错误#2030:检测到文件结束 错误#2006:索引超出范围

如果我在ByteArrays上添加操作,我设法读取第一个对象,但不是以下内容。

s.readBytes(tmp,tmp.length);
content = clone(tmp);
(content.readObject());
trace("########################## OK OBJECT RECEIVED");
var ack:FlexAck = (tmp.readObject() as FlexAck); 
trace("**********************> id = "+ack.id);

我花了很多时间尝试在几个论坛中找到一些东西,但没有任何帮助。

所以,如果有人能帮助我,那就太好了。

由于

西尔

编辑:

这是一个我认为应该有效的例子,但我不希望它能更好地说明我的目标(永久连接套接字和消息交换)。

Java类:

import java.net.ServerSocket;
import java.net.Socket;
import awl.oscare.protocol.AckOrder;
import flex.messaging.io.SerializationContext;
import flex.messaging.io.amf.Amf3Input;
import flex.messaging.io.amf.Amf3Output;


public class Main {
public static void main(String[] args) {
        while(true)
        {
        try {
        ServerSocket servSoc = new ServerSocket(8888);
        Socket s = servSoc.accept();
        System.out.println("connection accepted");
        Amf3Output amf3Output = new Amf3Output(SerializationContext.getSerializationContext());
        amf3Output.setOutputStream(s.getOutputStream());
        Amf3Input amf3Input = new Amf3Input(SerializationContext.getSerializationContext());
        amf3Input.setInputStream(s.getInputStream());
        while(true)
        {
            try
            {
                System.out.println("Reading object");
                Object obj = amf3Input.readObject();
                if(obj!=null)
                {
                    System.out.println(obj.getClass());
                    if (obj instanceof AckOrder)
                    {
                        AckOrder order = new AckOrder();
                          order.setId(((AckOrder)obj).getId());
order.setName(((AckOrder)obj).getName());
                          order.setSource(((AckOrder)obj).getSource());
                        order.setAckGroup(((AckOrder)obj).isAckGroup());
                          System.out.println(((AckOrder)obj).getId());
                        amf3Output.writeObject(order);
                        amf3Output.writeObjectEnd();
                        amf3Output.flush();
                    }
                }
            }
            catch (Exception e)
            {
                e.printStackTrace();
                break;
            }
        }
        amf3Output.close();
        amf3Input.close();
        servSoc.close();
    } catch (Exception e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    }

}
}

Java Serializable对象:

package protocol;

import java.io.Serializable;

public class AckOrder implements Serializable {
  private static final long serialVersionUID = 5106528318894546695L;
  private String id;
private String name;
private String source;
private boolean ackGroup = false;

public String getId() {
    return this.id;
}

public void setId(String id) {
    this.id = id;
}

public String getName() {
    return this.name;
}

public void setName(String name) {
    this.name = name;
}

public void setSource(String source) {
    this.source = source;
}

public String getSource() {
    return this.source;
}

public void setAckGroup(boolean ackGroup) {
    this.ackGroup = ackGroup;
}

public boolean isAckGroup() {
    return this.ackGroup;
}

public AckOrder()
{
    super();
}
}

Flex Side:

主要灵活代码:

<fx:Script>
    <![CDATA[
        import mx.collections.ArrayCollection;
        import mx.controls.Alert;
        import mx.events.FlexEvent;
        import mx.utils.object_proxy;


        private var _socket:Socket = new Socket();;

        private function onCreationComplete():void
        {
            this._socket.connect("localhost",8888);
            this._socket.addEventListener(ProgressEvent.SOCKET_DATA, onData);
        }

        private function onData(e:ProgressEvent):void
        {

            if(this._socket.bytesAvailable)
            {
                this._socket.endian = Endian.LITTLE_ENDIAN;
                var objects:Array = [];
                try{
                    while(this._socket.bytesAvailable > 0)
                    {
                        objects.push(this._socket.readObject());
                    }
                }catch(e:Error){trace(e.message);}
                    trace("|"+(objects)+"|");
            }

        }

        protected function sendButton_clickHandler(event:MouseEvent):void
        {
            var tmp:FlexAck = new FlexAck;
            tmp.id="1";
            tmp.name="A";
            tmp.source="B";
            tmp.ackGroup=false;
            this._socket.writeObject(tmp);
            this._socket.flush();
        }


    ]]>
</fx:Script>
<s:Button x="0" y="0" name="send" label="Send" click="sendButton_clickHandler(event)"/>

Flex可序列化对象:

package
{

[Bindable]
[RemoteClass(alias="protocol.AckOrder")] 
public class FlexAck
{
    public function FlexAck()
    {
    }

    public var id:String;
    public var name:String;
    public var source:String;
    public var ackGroup:Boolean;

}
}

编辑25/05/2011:

我在我的flex代码中添加了这些监听器:

this._socket.addEventListener(Event.ACTIVATE,onActivate);
                this._socket.addEventListener(Event.CLOSE,onClose);
                this._socket.addEventListener(Event.CONNECT,onConnect);
                this._socket.addEventListener(Event.DEACTIVATE,onDeactivate);
                this._socket.addEventListener(IOErrorEvent.IO_ERROR,onIOerror);
            this._socket.addEventListener(SecurityErrorEvent.SECURITY_ERROR,onSecurityError);

但是没有错误,我仍然无法正确接收对象。

3 个答案:

答案 0 :(得分:1)

您必须在服务器上发送AMF数据作为ByteArray:

final ByteArrayOutputStream baos = new ByteArrayOutputStream();
amf3Output.setOutputStream(baos);
amf3Output.writeObject(order);
amf3Output.flush();
amf3Output.close();
s.getOutputStream().write(baos.toByteArray());

然后

this._socket.readObject()

按预期工作!

答案 1 :(得分:1)

嗨问题是由以下原因引起的:

  1. AMF流是有状态的。当它序列化对象时,它会相对于已经写入的对象压缩它们。

  2. 通过使用索引引用先前发送的类描述,字符串值和对象来实现压缩(例如,如果您发送的第一个字符串是“heloWorld”,当您稍后发送该字符串时,将发送AMF流字符串索引0)。

  3. 不幸的是,ByteArray和Socket不维护readObject调用之间的引用表。因此,即使您继续将新读取的对象附加到同一ByteArray对象的末尾,每次调用readObject都会实例化新的引用表,丢弃以前创建的引用表(这意味着它应该适用于对对象树中相同字符串的重复引用)

  4. 在您的示例中,您始终将相同的字符串值写入属性。因此,当您发送第二个对象时,其字符串属性不会被序列化为字符串,而是作为对先前写入的对象中的字符串的引用。

  5. 解决方案是为您发送的每个对象创建一个新的AMF流。

    这当然是完全垃圾(!)这意味着我们无法在自定义协议中真正利用压缩。如果我们的协议可以决定何时重置这些参考表,可能会更好,也许当它们变得太大时。

    例如,如果你有一个RPC协议,那么让一个AMF流将远程方法名称作为引用传递而不是速度字符串的字符串会很好...

    我没有检查,但我认为这种事情是由RTMP完成的。它可能不会在像ByteArray和Socket这样的开发人员对象中被提供的原因(叹息,我希望这不是真的)是因为Adobe希望将我们推向LCDS ......

    附录/编辑:刚发现这个,它提供了解决方案http://code.google.com/p/cvlib/

答案 2 :(得分:0)

looking at the code之后,我认为你想在Java端做的是:

for(int i=0;i<10;i++){
    ack = new AckOrder(i,"A","B", true);
    amf3Output.writeObject(ack);
}
amf3Output.flush();

当您执行'flush'时,您将通过套接字发送信息,因此您一次只能发送一个对象。在Flex端,你应该总是试着看看对象的长度是多少,并确保你没有检查它会导致这个错误。

编辑:

private var _socket:Socket = new Socket();

private function onCreationComplete():void
{
    // Add connection socket info here
    this._socket.addEventListener(ProgressEvent.SOCKET_DATA, onData);
}

// This gets called every time we get new info, as in after the server flushes
private function onData(e:ProgressEvent):void
{
    if(this._socket.bytesAvailable)
    {
        this._socket.endian = Endian.LITTLE_ENDIAN; // Might not be needed, but often is
        // Try to get objects
        var objects:Array = [];
        try{
            while(this._socket.bytesAvailable > 0)
            {
                objects.push(this._socket.readObject());
            }
        }catch(e:Error){}
        // Do something with objects array
    }
}

onData函数被连续调用(每次服务器发送信息时),因为一切都是异步