mina处理断包和粘包

来源:互联网 发布:表格怎么做数据筛选 编辑:程序博客网 时间:2024/05/19 04:02

一.  解码方法
mina中有个内置类CumulativeProtocolDecoder是专门用来处理断包和粘包的。该类的api文档中有个实现的例子。
类org.apache.mina.filter.codec.CumulativeProtocolDecoder

public abstract class CumulativeProtocolDecoder extends ProtocolDecoderAdapter {    private final AttributeKey BUFFER = new AttributeKey(getClass(), "buffer");    public void decode(IoSession session, IoBuffer in,            ProtocolDecoderOutput out) throws Exception {        if (!session.getTransportMetadata().hasFragmentation()) {       //用来判断是否还有分帧(断包)            while (in.hasRemaining()) {                if (!doDecode(session, in, out)) {                    break;                }            }            return;        }             ////处理断包,省略      ............................................    }    //需要实现的方法    protected abstract boolean doDecode(IoSession session, IoBuffer in,            ProtocolDecoderOutput out) throws Exception;}

CumulativeProtocolDecoder是一个抽象类,必须继承并实现其doDecode方法,用户自定义协议的拆分就应该写在doDecode方法中,下面的类MessageDecoder是一个实现的例子。MessageDecoder解码网络数据到一种有两字节长度头的自定义消息协议格式。

/** * 断包和粘包处理,处理后的消息为一个或多个完整的数据消息 * @author blc */public class MessageDecoder extends CumulativeProtocolDecoder {    /*     * (non-Javadoc)     *      * @see     * org.apache.mina.filter.codec.CumulativeProtocolDecoder#doDecode(org.apache     * .mina.core.session.IoSession, org.apache.mina.core.buffer.IoBuffer,     * org.apache.mina.filter.codec.ProtocolDecoderOutput)     */    @Override    protected boolean doDecode(IoSession session, IoBuffer in,            ProtocolDecoderOutput out) throws Exception {                in.order(ServerConfig.ByteEndian);    //字节序, ServerConfig.ByteEndian = ByteOrder.LITTLE_ENDIAN                //消息buf        IoBuffer buf = IoBuffer.allocate(ServerConfig.MessageMaxByte);   //ServerConfig.MessageMaxByte 最大消息字节数        buf.order(ServerConfig.ByteEndian);                //考虑以下几种情况:        //    1. 一个ip包中只包含一个完整消息        //    2. 一个ip包中包含一个完整消息和另一个消息的一部分        //    3. 一个ip包中包含一个消息的一部分        //    4. 一个ip包中包含两个完整的数据消息或更多(循环处理在父类的decode中)        if (in.remaining() > 1) {            int length = in.getShort(in.position());if (length < 4) {                throw new ServerException("Error net message. (Message Length="+length+")");            }            if (length > ServerConfig.MessageMaxByte) {                throw new ServerException("Error net message. Message Length("+length+") > MessageMaxByte("+ServerConfig.MessageMaxByte+")");            }            if (length > in.remaining()) return false;            //复制一个完整消息            byte[] bytes = new byte[length];            in.get(bytes);            buf.put(bytes);                        buf.flip();            out.write(buf);            return true;        } else {            return false;        }    }}

二.  使用
将上面的解码器作为一个过滤器配置到mina中即可,在spring中的配置方法如下:

 <!-- 协议过滤器,包括解码和译码 -->    <bean id="protocolCodecFilter" class="org.apache.mina.filter.codec.ProtocolCodecFilter">        <constructor-arg>            <bean id="factory" class="server.ClientConnServer.MessageCodecFactory"></bean>        </constructor-arg>    </bean>    <!-- 将协议过滤器配置到mina的过滤链中 -->    <bean id="filterChainBuilder" class="org.apache.mina.core.filterchain.DefaultIoFilterChainBuilder">        <property name="filters">            <map>                <entry key="protocolCodecFilter" value-ref="protocolCodecFilter" />            </map>        </property>    </bean>    <!-- 处理器 -->    <bean id="clientConnHandler" class="server.ClientConnServer.ClientConnHandler" />    <!-- socket接收器,接收客户端连接 -->    <bean id="ioAcceptor" class="org.apache.mina.transport.socket.nio.NioSocketAcceptor" destroy-method="unbind">        <!--        <property name="defaultLocalAddress" value=":161" />-->        <property name="handler" ref="clientConnHandler" />        <property name="reuseAddress" value="true" />        <property name="filterChainBuilder" ref="filterChainBuilder" />    </bean>

要配置协议过滤器,必须使用一个ProtocolCodecFactory ,下面是简单实现

public class MessageCodecFactory implements ProtocolCodecFactory {    private final MessageEncoder encoder;    private final MessageDecoder decoder;        public MessageCodecFactory() {        encoder = new MessageEncoder();        decoder = new MessageDecoder();    }    /* (non-Javadoc)     * @see org.apache.mina.filter.codec.ProtocolCodecFactory#getDecoder(org.apache.mina.core.session.IoSession)     */    @Override    public ProtocolDecoder getDecoder(IoSession session) throws Exception {        return decoder;    }    /* (non-Javadoc)     * @see org.apache.mina.filter.codec.ProtocolCodecFactory#getEncoder(org.apache.mina.core.session.IoSession)     */    @Override    public ProtocolEncoder getEncoder(IoSession session) throws Exception {        return encoder;    }}/** * 译码器,不做任何事情 */public class MessageEncoder extends ProtocolEncoderAdapter {    /* (non-Javadoc)     * @see org.apache.mina.filter.codec.ProtocolEncoder#encode(org.apache.mina.core.session.IoSession, java.lang.Object, org.apache.mina.filter.codec.ProtocolEncoderOutput)     */    @Override    public void encode(IoSession session, Object message,            ProtocolEncoderOutput out) throws Exception {        //Do nothing    }}




转载地址:http://blianchen.blog.163.com/blog/static/1310562992010101891522100/