Mina使用AMF3与Flash Socket通信的"粘包"问题

本文介绍了在Mina框架中,服务端使用AMF3编码和压缩数据后通过Socket发送给Flash客户端时遇到的'粘包'问题。服务端需要先压缩数据,再写入输出流,以避免数据丢失。客户端接收到数据后,需循环读取并解压每个数据块。文中详细展示了服务端的AMF3编码和解码实现,以及客户端的处理流程。
摘要由CSDN通过智能技术生成
项目结构图如下:
Mina使用AMF3与Flash Socket通信的粘包问题 - abjuration - abjuration
方式: 服务端通过把要发送的数据(这里发送的是对象)编码为amf3格式, 再通过java.util.zip.Deflater 进行压缩,再把压缩后的数据发往客户端.
         客户端通过ByteArray.uncompress() 方法解压, 再通过
ByteArray. readObject()方法读取数据(服务端发送的是对象).
mina的文章网上很多, 此项目不再解释.
复制代码即可运行.
说明: 由于使用的nio流在进行数据的传输,所以当服务端同时向客户端发送多次数据时(假如同时发送10次),它并不是发送10次,而是将数据进行整合发送,也就是一般发送少于10次. 如下图:
Mina使用AMF3与Flash Socket通信的粘包问题 - abjuration - abjuration
 
(服务端发送了若干数据,但最终被整合成2个数据段发往客户端. 会触发flash的两次 ProgressEvent.SOCKET_DATA事件)
这个时候客户端在收到"数据段1"后: 通过ByteArray.readObject() 读取对象数据时, 一次只会读取一个数据, 所以要循环读取.
但 这里有个问题, 如果是在服务端先通过amf3output.writeObject(...)写入ByteArrayOutputStream中, 再对ByteArrayOutputStream进行压缩, 那么在客户端解压后, 会出现数据丢失的情况, 即解压后只保留了"数据1", 后面的丢失.
所以服务端要处理为: 先压缩, 再把压缩后的数据写入ByteArrayOutputStream, 再发送给客户端. 客户端接收到后, 循环取出每个数据, 再解压获取真正的数据.

服务端:
AMF3CodecFactory:

package com.test.filter.amf3;

import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.ProtocolCodecFactory;
import org.apache.mina.filter.codec.ProtocolDecoder;
import org.apache.mina.filter.codec.ProtocolEncoder;

public class AMF3CodecFactory implements ProtocolCodecFactory {
private ProtocolEncoder encoder;
private ProtocolDecoder decoder;

public AMF3CodecFactory() {
encoder = new AMF3Encoder();
decoder = new AMF3Decoder();
}

public ProtocolDecoder getDecoder(IoSession session) throws Exception {
return decoder;
}

public ProtocolEncoder getEncoder(IoSession session) throws Exception {
return encoder;
}
}

AMF3Decoder:
package com.test.filter.amf3;

import java.util.zip.InflaterInputStream;
import java.io.DataInputStream;
import java.io.UnsupportedEncodingException;

import flex.messaging.io.SerializationContext;
import flex.messaging.io.amf.Amf3Input;
import flex.messaging.io.amf.ASObject;

import org.apache.mina.core.buffer.IoBuffer;
import org.apache.mina.core.session.AttributeKey;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.CumulativeProtocolDecoder;
import org.apache.mina.filter.codec.ProtocolDecoderOutput;
/**
 * <style type="text/css">body{background:#C7EDCC;}</style>
 * 解码
 * AMF3Decoder.java
 * @author yan
 *
 */
public class AMF3Decoder extends CumulativeProtocolDecoder {
private final AttributeKey POLICY = new AttributeKey(this.getClass(), "policy");
private final String security = "<policy-file-request/>";
private final SerializationContext context = new SerializationContext();
private final Amf3Input amf3in;
public AMF3Decoder() {
amf3in = new Amf3Input(context);
}
protected boolean doDecode(IoSession session, IoBuffer in,
ProtocolDecoderOutput out) throws Exception {
if(this.isSecurityRequest(session,in)){
out.write(security);
in.free();
return true;
}else{
in.position(0);
//获取flash socket传入的信息.此时客户端传入的是一个as对象
amf3in.setInputStream(new InflaterInputStream(new DataInputStream(in.asInputStream())));
Object message = amf3in.readObject();
if(message instanceof ASObject){
out.write(message);
in.free();
return true;
}else{
in.free();
return false;
}
}
}
/**
* <style type="text/css">body{background:#C7EDCC;}</style>
* 是否为策略文件请求
* @param session
* @param in
* @return
*/
private boolean isSecurityRequest(IoSession session, IoBuffer in){
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值