ApacheMINA粘包、拆包的正确实现(网上常见的代码有bug)

概要:

ApacheMINA粘包、拆包的正确实现(网上常见的代码有bug)

| |目录

粘包拆包的关键在于数据协议,通俗的讲就是我们要约定数据包的格式,

这个实例中的格式是(4个字节长度+json字符串)

1.

import org.apache.mina.common.IoSession;
import org.apache.mina.filter.codec.ProtocolCodecFactory;
import org.apache.mina.filter.codec.ProtocolDecoder;
import org.apache.mina.filter.codec.ProtocolEncoder;
/**
 * @author Mr.Xia
 */
public class MessageCodecFactory implements ProtocolCodecFactory {
    private final DataEncoderEx encoder;
    private final DataDecoderEx decoder;
    
    public MessageCodecFactory() {
        encoder = new DataEncoderEx();
        decoder = new DataDecoderEx();
    }

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

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


2.

import java.nio.charset.Charset;

import org.apache.mina.common.IoBuffer;
import org.apache.mina.common.IoSession;
import org.apache.mina.filter.codec.ProtocolEncoderAdapter;
import org.apache.mina.filter.codec.ProtocolEncoderOutput;
/**
 * @author Mr.Xia
 */
public class DataEncoderEx extends ProtocolEncoderAdapter {

	public void encode(IoSession session, Object message,
			ProtocolEncoderOutput out) throws Exception {
		System.out.println(message);
		IoBuffer buf = IoBuffer.allocate(100).setAutoExpand(true);
		String strOut = message.toString();
		buf.putInt(strOut.getBytes(Charset.forName("utf-8")).length);
		buf.putString(strOut, Charset.forName("utf-8").newEncoder());
		buf.flip();
		out.write(buf);
	}

}

3.

import org.apache.mina.common.IoBuffer;
import org.apache.mina.common.IoSession;
import org.apache.mina.filter.codec.CumulativeProtocolDecoder;
import org.apache.mina.filter.codec.ProtocolDecoderOutput;
/**
 * @author Mr.Xia
 */
public class DataDecoderEx extends CumulativeProtocolDecoder {

	@Override
	protected boolean doDecode(IoSession session, IoBuffer in,ProtocolDecoderOutput out) throws Exception {

		if (in.remaining() < 4)// 这里很关键,网上很多代码都没有这句,是用来当拆包时候剩余长度小于4的时候的保护,不加会出错
		{
			return false;
		}
		if (in.remaining() > 1) {

			in.mark();// 标记当前位置,以便reset
			int length = in.getInt(in.position());

			if (length > in.remaining() - 4) {// 如果消息内容不够,则重置,相当于不读取size
				System.out.println("package notenough  left=" + in.remaining()+ " length=" + length);
				in.reset();
				return false;// 接收新数据,以拼凑成完整数据
			} else {
				System.out.println("package =" + in.toString());
				in.getInt();

				byte[] bytes = new byte[length];
				in.get(bytes, 0, length);
				String str = new String(bytes, "UTF-8");
				if (null != str && str.length() > 0) {
					String strOut = str;// 别看这里的处理,这里是我的数据包解密算法~你可以直接拿str当数据
					out.write(strOut);
				}
				if (in.remaining() > 0) {// 如果读取内容后还粘了包,就让父类再给一次,进行下一次解析
					// System.out.println("package left="+in.remaining()+" data="+in.toString());
				}
				return true;// 这里有两种情况1:没数据了,那么就结束当前调用,有数据就再次调用
			}
		}
		return false;// 处理成功,让父类进行接收下个包
	}
}


评论关闭
评论 还能输入200
评论关闭
评论 还能输入200
资料加载中...
已关注 , 取消