Чтение объекта AMF с помощью гнезда flex - PullRequest
5 голосов
/ 18 мая 2011

В настоящее время я пытаюсь установить связь между java и flex, используя сокеты и сериализованные объекты AMF.

На стороне java я использую Amf3Input и Amf3Output из BlazeDS (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 () как 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 Сериализуемый объект:

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:

Основной гибкий код:

<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:

Я добавил этих слушателей в свой гибкий код:

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 ]

1 голос
/ 20 октября 2011

Вы должны отправить данные 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 голос
/ 02 мая 2012

Привет, проблема вызвана следующим:

  1. Поток AMF с состоянием.Когда он сериализует объекты, он сжимает их относительно объектов, которые уже были записаны.

  2. Сжатие достигается путем ссылки на ранее отправленные описания классов, строковые значения и объекты с использованием индексов (например, если первая отправленная вами строка была «heloWorld», когда вы позже отправляете эту строкупоток AMF будет отправлять строку с индексом 0).

  3. К сожалению, ByteArray и Socket не поддерживают справочные таблицы между вызовами readObject.Таким образом, даже если вы продолжаете добавлять вновь прочитанные объекты в конец одного и того же объекта ByteArray, каждый вызов readObject создает новые таблицы ссылок, отбрасывая ранее созданные (это означает, что он должен работать для повторных ссылок на одну и ту же строку в дереве объектов).)

  4. В вашем примере вы всегда записываете в свойства одинаковые строковые значения.Таким образом, когда вы отправляете второй объект, его строковые свойства не сериализуются как строки, а как ссылки на строки в ранее написанном объекте.

Решением является создание новой AMFпоток для каждого отправляемого вами объекта.

Это полный мусор, конечно (!) Это означает, что мы не можем использовать сжатие в пользовательских протоколах.Было бы намного лучше, если бы наши протоколы могли решить, когда следует сбросить эти справочные таблицы, возможно, когда они станут слишком большими.

Например, если у вас есть протокол RPC, было бы неплохо иметь поток AMFпередавать имена удаленных методов как ссылки, а не как строки для скорости ...

Я не проверял, но я думаю, что такого рода вещи сделаны RTMP.Причина, по которой он, вероятно, не был бы доступен в объектах разработчика, таких как ByteArray и Socket (вздох, я надеюсь, что это не так), заключается в том, что Adobe хочет подтолкнуть нас к LCDS ...

Добавление / редактировать: только что нашел это, что обеспечивает решение http://code.google.com/p/cvlib/

0 голосов
/ 18 мая 2011

После глядя на код , я думаю, что вы хотите сделать на стороне Java следующее:

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

Когда вы выполняете «сброс», вы отправляете информациючерез сокет, чтобы вы могли отправлять только один объект за раз.На конце Flex вы должны всегда пытаться увидеть, какова длина объекта, и убедиться, что вы не пересекаете его, что может привести к этой ошибке.Функция onData вызывается постоянно (каждый раз, когда сервер отправляет информацию), так как все асинхронно .

...