上一篇中,我们介绍了如何在mina中编写自己的日志过滤器,这一篇我们自己实现一个编解器。 实际应用当,很多应用系统应用的都不是标准的web service或XML等,比如象中国移动/联通/电信的短信网关程序,都有自己不同的协议实现,并且都是基于TCP/IP的字节流。Mina自带的编解码器实现了TextLineEncoder和TextLineDecoder,可以进行按行的字符串处理,对于象短信网关程序,就要自己实现编解码过滤器了。 我们定义一个简单的基于TCP/IP字节流的协议,实现在客户端和服务端之间的数据包传输。数据包MyProtocalPack有消息头和消息体组成,消息头包括:length(消息包的总长度,数据类型int),flag(消息包标志位,数据类型byte),消息体content是一个字符串,实际实现的时候按byte流处理。源代码如下: view plaincopy to clipboardprint? package com.gftech.mytool.mina; import com.gftech.util.GFCommon; public class MyProtocalPack { private int length; private byte flag; private String content; public MyProtocalPack(){ } public MyProtocalPack(byte flag,String content){ this.flag=flag; this.content=content; int len1=content==null?0:content.getBytes().length; this.length=5+len1; } public MyProtocalPack(byte[] bs){ if(bs!=null && bs.length>=5){ length=GFCommon.bytes2int(GFCommon.bytesCopy(bs, 0, 4)); flag=bs[4]; content=new String(GFCommon.bytesCopy(bs, 5, length-5)); } } public int getLength() { return length; } public void setLength(int length) { this.length = length; } public byte getFlag() { return flag; } public void setFlag(byte flag) { this.flag = flag; } public String getContent() { return content; } public void setContent(String content) { this.content = content; } public String toString(){ StringBuffer sb=new StringBuffer(); sb.append(" Len:").append(length); sb.append(" flag:").append(flag); sb.append(" content:").append(content); return sb.toString(); } } package com.gftech.mytool.mina; import com.gftech.util.GFCommon; public class MyProtocalPack { private int length; private byte flag; private String content; public MyProtocalPack(){ } public MyProtocalPack(byte flag,String content){ this.flag=flag; this.content=content; int len1=content==null?0:content.getBytes().length; this.length=5+len1; } public MyProtocalPack(byte[] bs){ if(bs!=null && bs.length>=5){ length=GFCommon.bytes2int(GFCommon.bytesCopy(bs, 0, 4)); flag=bs[4]; content=new String(GFCommon.bytesCopy(bs, 5, length-5)); } } public int getLength() { return length; } public void setLength(int length) { this.length = length; } public byte getFlag() { return flag; } public void setFlag(byte flag) { this.flag = flag; } public String getContent() { return content; } public void setContent(String content) { this.content = content; } public String toString(){ StringBuffer sb=new StringBuffer(); sb.append(" Len:").append(length); sb.append(" flag:").append(flag); sb.append(" content:").append(content); return sb.toString(); } } 回过头来,我们先看一下在MinaTimeServer中,如何使用一个文本的编解码过滤器,它是在过滤器链中添加了一个叫ProtocalCodecFilter的类,其中它调用了一个工厂方法TextLineCodecFactory的工厂类,创建具休的TextLineEncoder和TextLineDecoder编码和解码器。我们看一下具体的源代码:view plaincopy to clipboardprint? acceptor.getFilterChain().addLast("codec", new ProtocolCodecFilter(new TextLineCodecFactory(Charset.forName("GBK")))); acceptor.getFilterChain().addLast("codec", new ProtocolCodecFilter(new TextLineCodecFactory(Charset.forName("GBK")))); view plaincopy to clipboardprint? package org.apache.mina.filter.codec.textline; import java.nio.charset.Charset; import org.apache.mina.core.buffer.BufferDataException; 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; /** * A {@link ProtocolCodecFactory} that performs encoding and decoding between * a text line data and a Java string object. This codec is useful especially * when you work with a text-based protocols such as SMTP and IMAP. * * @author The Apache MINA Project (dev@mina.apache.org) * @version $Rev$, $Date$ */ public class TextLineCodecFactory implements ProtocolCodecFactory { private final TextLineEncoder encoder; private final TextLineDecoder decoder; /** * Creates a new instance with the current default {@link Charset}. */ public TextLineCodecFactory() { this(Charset.defaultCharset()); } /** * Creates a new instance with the specified {@link Charset}. The * encoder uses a UNIX {@link LineDelimiter} and the decoder uses * the AUTO {@link LineDelimiter}. * * @param charset * The charset to use in the encoding and decoding */ public TextLineCodecFactory(Charset charset) { encoder = new TextLineEncoder(charset, LineDelimiter.UNIX); decoder = new TextLineDecoder(charset, LineDelimiter.AUTO); } /** * Creates a new instance of TextLineCodecFactory. This constructor * provides more flexibility for the developer. * * @param charset * The charset to use in the encoding and decoding * @param encodingDelimiter * The line delimeter for the encoder * @param decodingDelimiter * The line delimeter for the decoder */ public TextLineCodecFactory(Charset charset, String encodingDelimiter, String decodingDelimiter) { encoder = new TextLineEncoder(charset, encodingDelimiter); decoder = new TextLineDecoder(charset, decodingDelimiter); } /** * Creates a new instance of TextLineCodecFactory. This constructor * provides more flexibility for the developer. * * @param charset * The charset to use in the encoding and decoding * @param encodingDelimiter * The line delimeter for the encoder * @param decodingDelimiter * The line delimeter for the decoder */ public TextLineCodecFactory(Charset charset, LineDelimiter encodingDelimiter, LineDelimiter decodingDelimiter) { encoder = new TextLineEncoder(charset, encodingDelimiter); decoder = new TextLineDecoder(charset, decodingDelimiter); } public ProtocolEncoder getEncoder(IoSession session) { return encoder; } public ProtocolDecoder getDecoder(IoSession session) { return decoder; } /** * Returns the allowed maximum size of the encoded line. * If the size of the encoded line exceeds this value, the encoder * will throw a {@link IllegalArgumentException}. The default value * is {@link Integer#MAX_VALUE}. * <p> * This method does the same job with {@link TextLineEncoder#getMaxLineLength()}. */ public int getEncoderMaxLineLength() { return encoder.getMaxLineLength(); } /** * Sets the allowed maximum size of the encoded line. * If the size of the encoded line exceeds this value, the encoder * will throw a {@link IllegalArgumentException}. The default value * is {@link Integer#MAX_VALUE}. * <p> * This method does the same job with {@link TextLineEncoder#s