我目前正在尝试使用套接字和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);
但是没有错误,我仍然无法正确接收对象。
答案 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)
嗨问题是由以下原因引起的:
AMF流是有状态的。当它序列化对象时,它会相对于已经写入的对象压缩它们。
通过使用索引引用先前发送的类描述,字符串值和对象来实现压缩(例如,如果您发送的第一个字符串是“heloWorld”,当您稍后发送该字符串时,将发送AMF流字符串索引0)。
不幸的是,ByteArray和Socket不维护readObject调用之间的引用表。因此,即使您继续将新读取的对象附加到同一ByteArray对象的末尾,每次调用readObject都会实例化新的引用表,丢弃以前创建的引用表(这意味着它应该适用于对对象树中相同字符串的重复引用)
在您的示例中,您始终将相同的字符串值写入属性。因此,当您发送第二个对象时,其字符串属性不会被序列化为字符串,而是作为对先前写入的对象中的字符串的引用。
解决方案是为您发送的每个对象创建一个新的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函数被连续调用(每次服务器发送信息时),因为一切都是异步。