`
Donald_Draper
  • 浏览: 981326 次
社区版块
存档分类
最新评论

Mina 协议编解码过滤器一(协议编解码工厂、协议编码器)

    博客分类:
  • Mina
阅读更多
MINA TCP简单通信实例:http://donald-draper.iteye.com/blog/2375297
MINA 编解码器实例:http://donald-draper.iteye.com/blog/2375317
MINA 多路分离解码器实例:http://donald-draper.iteye.com/blog/2375324
Mina Socket会话配置:http://donald-draper.iteye.com/blog/2375529
Mina 过滤链默认构建器:http://donald-draper.iteye.com/blog/2375985
Mina 过滤器定义:http://donald-draper.iteye.com/blog/2376161
Mina 日志过滤器与引用计数过滤器:http://donald-draper.iteye.com/blog/2376226
Mina 过滤链抽象实现:http://donald-draper.iteye.com/blog/2376335
Mina Socket与报文过滤链:http://donald-draper.iteye.com/blog/2376440
引言:
上面几篇文章我们简单看了一下Socket会话配置,过滤器及过滤链;在TCP简单通信实例这篇文章中,有这么一段代码:
//配置过滤器
DefaultIoFilterChainBuilder defaultIoFilterChainBuilder = acceptor.getFilterChain();
LoggingFilter loggingFilter = new LoggingFilter();
defaultIoFilterChainBuilder.addLast("loggingFilter", loggingFilter);
TextLineCodecFactory textLineCodecFactory = 
        new TextLineCodecFactory(charset,LineDelimiter.WINDOWS.getValue(),
		 LineDelimiter.WINDOWS.getValue());
ProtocolCodecFilter protocolCodecFilter = new ProtocolCodecFilter(textLineCodecFactory);
defaultIoFilterChainBuilder.addLast("protocolCodecFilter",protocolCodecFilter);

前面我们看过日志过滤器,今天我们来看一下协议编解码过滤器ProtocolCodecFilter。

/**
 * An {@link IoFilter} which translates binary or protocol specific data into
 * message object and vice versa using {@link ProtocolCodecFactory},
 * {@link ProtocolEncoder}, or {@link ProtocolDecoder}.
 *
 * @author The Apache Directory Project (mina-dev@directory.apache.org)
 * @version $Rev$, $Date$
 */
public class ProtocolCodecFilter extends IoFilterAdapter
{
    private static final Logger LOGGER = LoggerFactory.getLogger(org/apache/mina/filter/codec/ProtocolCodecFilter);
    private static final Class EMPTY_PARAMS[] = new Class[0];
    private static final IoBuffer EMPTY_BUFFER = IoBuffer.wrap(new byte[0]);
    //编码器属性key
    private static final AttributeKey ENCODER = 
         new AttributeKey(org/apache/mina/filter/codec/ProtocolCodecFilter, "encoder");
    //编码器输出属性key
    private static final AttributeKey ENCODER_OUT = 
         new AttributeKey(org/apache/mina/filter/codec/ProtocolCodecFilter, "encoderOut");
    //解码器属性key
    private static final AttributeKey DECODER = 
         new AttributeKey(org/apache/mina/filter/codec/ProtocolCodecFilter, "decoder");  
    //解码器输出属性key
    private static final AttributeKey DECODER_OUT = 
         new AttributeKey(org/apache/mina/filter/codec/ProtocolCodecFilter, "decoderOut");
    private final ProtocolCodecFactory factory;//编解码器工厂协议
}

//属性key
public final class AttributeKey
    implements Serializable
{
    private static final long serialVersionUID = -583377473376683096L;
    private final String name;
    public AttributeKey(Class source, String name)
    {
        this.name = (new StringBuilder()).append(source.getName()).append('.').append(name).append('@').append(Integer.toHexString(hashCode())).toString();
    }
    public String toString()
    {
        return name;
    }
    public int hashCode()
    {
        int h = 629 + (name != null ? name.hashCode() : 0);
        return h;
    }
    public boolean equals(Object obj)
    {
        if(this == obj)
            return true;
        if(!(obj instanceof AttributeKey))
        {
            return false;
        } else
        {
            AttributeKey other = (AttributeKey)obj;
            return name.equals(other.name);
        }
    }
}

在往下看之前,我们先来看一下协议编解码工厂ProtocolCodecFactory
/**
 * Provides {@link ProtocolEncoder} and {@link ProtocolDecoder} which translates
 * binary or protocol specific data into message object and vice versa.
 * <p>协议编解码工厂ProtocolCodecFactory提供协议编码器和解码器,解码器二进制数据或
 协议数据到消息对象;编码器反之。
 * Please refer to
 * [url=../../../../../xref-examples/org/apache/mina/examples/reverser/ReverseProtocolProvider.html]<code>ReverserProtocolProvider</code>[/url]
 * example.
 *  
 * @author The Apache Directory Project (mina-dev@directory.apache.org)
 * @version $Rev$, $Date$
 */
public interface ProtocolCodecFactory {
    /**
     * Returns a new (or reusable) instance of {@link ProtocolEncoder} which
     * encodes message objects into binary or protocol-specific data.
     返回一个编码器实例,用于将消息对象编码成二进制或协议数据
     */
    ProtocolEncoder getEncoder() throws Exception;
    /**
     * Returns a new (or reusable) instance of {@link ProtocolDecoder} which
     * decodes binary or protocol-specific data into message objects.
     返回一个解码器实例,用于将二进制或协议数据解码成消息对象
     */
    ProtocolDecoder getDecoder() throws Exception;
}

从上可以看出,协议编解码工厂ProtocolCodecFactory提供协议编码器ProtocolEncoder和解码器ProtocolDecoder;编码器将消息对象编码成二进制或协议数据,解码器将二进制或协议数据解码成消息对象。

再来看编码器与解码器的定义,先来看编码器:
/**
 * Encodes higher-level message objects into binary or protocol-specific data.
 * MINA invokes {@link #encode(IoSession, Object, ProtocolEncoderOutput)}
 * method with message which is popped from the session write queue, and then
 * the encoder implementation puts encoded {@link ByteBuffer}s into
 * {@link ProtocolEncoderOutput} by calling
 * {@link ProtocolEncoderOutput#write(ByteBuffer)}.
 * <p>协议编码器用于编码上层的消息对象为二进制或协议数据。mina调用编码器的#encode
 方法将从会话写请求队列中pop的消息,然后调用ProtocolEncoderOutput#write
 方法将编码后的消息放在ByteBuffer。
 * Please refer to
 * [url=../../../../../xref-examples/org/apache/mina/examples/reverser/TextLineEncoder.html]<code>TextLineEncoder</code>[/url]
 * example. 
 * 
 * @author The Apache Directory Project (mina-dev@directory.apache.org)
 * @version $Rev$, $Date$
 */
public interface ProtocolEncoder {

    /**
     * Encodes higher-level message objects into binary or protocol-specific data.
     * MINA invokes {@link #encode(IoSession, Object, ProtocolEncoderOutput)}
     * method with message which is popped from the session write queue, and then
     * the encoder implementation puts encoded {@link ByteBuffer}s into
     * {@link ProtocolEncoderOutput}.
     * 协议编码器用于编码上层的消息对象为二进制或协议数据。mina调用编码器的#encode
      方法将从会话写请求队列中pop的消息,然后调用ProtocolEncoderOutput#write
     方法将编码后的消息放在ByteBuffer。
     * @throws Exception if the message violated protocol specification
     */
    void encode(IoSession session, Object message, ProtocolEncoderOutput out)
            throws Exception;

    /**
     * Releases all resources related with this encoder.
     * 释放编码器关联的所有资源
     * @throws Exception if failed to dispose all resources
     */
    void dispose(IoSession session) throws Exception;
}

//ProtocolEncoderAdapter
/**
 * An abstract {@link ProtocolEncoder} implementation for those who don't have any
 * resources to dispose.
 * ProtocolEncoderAdapter为协议编码的抽象实现,主要是对应没有任何资源要释放的协议编码。
 * @author The Apache Directory Project (mina-dev@directory.apache.org)
 * @version $Rev$, $Date$
 */
public abstract class ProtocolEncoderAdapter implements ProtocolEncoder {
    /**
     * Override this method dispose all resources related with this encoder.
     * The default implementation does nothing.
     重写dispose,释放相关资源,默认为does nothing
     */
    public void dispose(IoSession session) throws Exception {
    }
}

再来看协议编码输出ProtocolEncoderOutput
/**
 * Callback for {@link ProtocolEncoder} to generate encoded {@link ByteBuffer}s.
 * {@link ProtocolEncoder} must call {@link #write(ByteBuffer)} for each encoded
 * message.
 * 
 * @author The Apache Directory Project (mina-dev@directory.apache.org)
 * @version $Rev$, $Date$
 */
public interface ProtocolEncoderOutput {
    /**
     * Callback for {@link ProtocolEncoder} to generate encoded
     * {@link ByteBuffer}s. {@link ProtocolEncoder} must call
     * {@link #write(ByteBuffer)} for each encoded message.
     * 协议编码器回调此方法,编码消息到ByteBuffer
     * @param buf the buffer which contains encoded data
     */
    void write(ByteBuffer buf);

    /**
     * Merges all buffers you wrote via {@link #write(ByteBuffer)} into
     * one {@link ByteBuffer} and replaces the old fragmented ones with it.
     * This method is useful when you want to control the way MINA generates
     * network packets.
     合并所有通过#write(ByteBuffer)产生的字节buffer,replaces the old fragmented ones with it
     当你需要控制mina产生网络包的时候,此方非常有用。
     */
    void mergeAll();

    /**
     * Flushes all buffers you wrote via {@link #write(ByteBuffer)} to
     * the session.  This operation is asynchronous; please wait for
     * the returned {@link WriteFuture} if you want to wait for
     * the buffers flushed.
     * 刷新所有通过write(ByteBuffer)写到会话的字节buffer。此操作为异步;
     如果想等待buffer刷新完成,可以等待返回的结果WriteFuture
     * @return <tt>null</tt> if there is nothing to flush at all.
     */
    WriteFuture flush();
}

来看一下ProtocolEncoderOutput的简单实现
/**
 * A {@link ProtocolEncoderOutput} based on queue.
 *
 * @author The Apache Directory Project (mina-dev@directory.apache.org)
 * @version $Rev$, $Date$
 */
public abstract class SimpleProtocolEncoderOutput implements
        ProtocolEncoderOutput {
    private final Queue bufferQueue = new Queue();//buffer队列
    public SimpleProtocolEncoderOutput() {
    }
    public Queue getBufferQueue() {
        return bufferQueue;
    }
    //将buffer添加到buffer队列
    public void write(ByteBuffer buf) {
        bufferQueue.push(buf);
    }
    //合并
    public void mergeAll() {
        int sum = 0;
        final int size = bufferQueue.size();
        if (size < 2) {
            // no need to merge!,长度小2,不许要合并
            return;
        }
        // Get the size of merged BB,计算buffer队列中,所有buffer的实际数据容量
        for (int i = size - 1; i >= 0; i--) {
            sum += ((ByteBuffer) bufferQueue.get(i)).remaining();
        }
        // Allocate a new BB that will contain all fragments,创建一个容量为sum的字节buffer
        ByteBuffer newBuf = ByteBuffer.allocate(sum);
        // and merge all.
	//遍历buffer队列所有buffer,放在newBuf中,并释放原始buffer
        for (;;) {
            ByteBuffer buf = (ByteBuffer) bufferQueue.pop();
            if (buf == null) {
                break;
            }
            newBuf.put(buf);
            buf.release();
        }
        // Push the new buffer finally.读写模式切换
        newBuf.flip();
        bufferQueue.push(newBuf);//将合并后的buffer添加到buffer队列
    }
    //刷新buffer队列数据
    public WriteFuture flush() {
        Queue bufferQueue = this.bufferQueue;
        WriteFuture future = null;
        if (bufferQueue.isEmpty()) {
            return null;
        } else {
	    遍历buffer队列所有buffer,发送buffer数据
            for (;;) {
                ByteBuffer buf = (ByteBuffer) bufferQueue.pop();
                if (buf == null) {
                    break;
                }

                // Flush only when the buffer has remaining.
                if (buf.hasRemaining()) {
		    //委托给doFlush
                    future = doFlush(buf);
                }
            }
        }
        return future;
    }
    //待子类扩展
    protected abstract WriteFuture doFlush(ByteBuffer buf);
}


从上面可以看出编码器ProtocolEncoder主要有两个方法,encode和dispose;
encode用于,编码上层的消息对象为二进制或协议数据。mina调用编码器的#encode
方法将从会话写请求队列中pop的消息,然后调用ProtocolEncoderOutput#write方法将编码后的消息放在ByteBuffer;dispose方法释放编码器资源。ProtocolEncoderAdapter为编码器抽象实现,默认实现了dispose,不做任何事情,对于不需要释放资源的编码器继承ProtocolEncoderAdapter。ProtocolEncoderOutput主要的工作是将协议编码器编码后的
字节buffer,缓存起来,等待flush方法调用时,则将数据发送出去。SimpleProtocolEncoderOutput为ProtocolEncoderOutput的简单实现内部有一个buffer队列bufferQueue(Queue),用于存放write(ByteBuffer)方法,传入的字节buffer;mergeAll方法为合并buffer队列的所有buffer数据到一个buffer;flush方法为发送buffer队列中的所有buffer,实际发送工作委托给doFlush方法待子类实现。

来看协议编解码过滤器ProtocolCodecFilter的ProtocolEncoderOutput的内部实现:
private static class ProtocolEncoderOutputImpl extends
            SimpleProtocolEncoderOutput {
        private final IoSession session;

        private final NextFilter nextFilter;

        private final WriteRequest writeRequest;

        public ProtocolEncoderOutputImpl(IoSession session,
                NextFilter nextFilter, WriteRequest writeRequest) {
            this.session = session;
            this.nextFilter = nextFilter;
            this.writeRequest = writeRequest;
        }
       //doFlush
        protected WriteFuture doFlush(ByteBuffer buf) {
	   //创建写操作返回结果
            WriteFuture future = new DefaultWriteFuture(session);
	    //将会话写事件filterWrite传递给下一个过滤器
            nextFilter.filterWrite(session, new WriteRequest(
                    new HiddenByteBuffer(buf), future, writeRequest
                            .getDestination()));
            return future;
        }
    }

ProtocolEncoderOutputImpl的doFlush,首先将会话包装成DefaultWriteFuture,
将会话,写请求信息传递给NextFilter
//ProtocolCodecFilter
private static class HiddenByteBuffer extends ByteBufferProxy {
    private HiddenByteBuffer(ByteBuffer buf) {
        super(buf);
    }
}

/**
 * A {@link ByteBuffer} that wraps a buffer and proxies any operations to it.
 * <p>ByteBufferProxy可以理解为字节buffer的静态代理,所有的方法都是委托给内部的字节buf。
 * You can think this class like a {@link FilterOutputStream}.  All operations
 * are proxied by default so that you can extend this class and override existing
 * operations selectively.  You can introduce new operations, too.
 * 这个有点像FilterOutputStream,所有的代理操作默认都是通过内部buf完成,
 亦可以选择重新一些方法
 * @author The Apache Directory Project (mina-dev@directory.apache.org)
 * @version $Rev$, $Date$
 */
public class ByteBufferProxy extends ByteBuffer {
    /**
     * The buffer proxied by this proxy.
     */
    protected ByteBuffer buf;
    /**
     * Create a new instance.
     * @param buf the buffer to be proxied
     */
    protected ByteBufferProxy(ByteBuffer buf) {
        if (buf == null) {
            throw new NullPointerException("buf");
        }
        this.buf = buf;
    }
    public void acquire() {
        buf.acquire();
    }
    public void release() {
        buf.release();
    }
    public ByteBuffer flip() {
        buf.flip();
        return this;
    }
    ...
    从上面看所有方法都是委托给内部buf
}

这一篇,我们先看到这,自此我们了协议编解码过滤器的内部协议编解码工厂ProtocolCodecFactory,及内部的ProtocolEncoderOutputImpl,先来总结一下,至于协议编解码工厂在协议编解码过滤器ProtocolCodecFilter中的作用我们在后面的文章再说。
总结:

   协议编解码过滤器ProtocolCodecFilter关联一个协议编解码工厂ProtocolCodecFactory,协议编解码工厂提供协议编码器ProtocolEncoder和解码器ProtocolDecoder;编码器将消息对象编码成二进制或协议数据,解码器将二进制或协议数据解码成消息对象。编码器ProtocolEncoder主要有两个方法,encode和dispose;encode用于,编码上层的消息对象为二进制或协议数据。mina调用编码器的#encode方法将从会话写请求队列中pop的消息,然后调用ProtocolEncoderOutput#write方法将编码后的消息放在ByteBuffer;dispose方法释放编码器资源。ProtocolEncoderAdapter为编码器抽象实现,默认实现了dispose,不做任何事情,对于不需要释放资源的编码器继承ProtocolEncoderAdapter。ProtocolEncoderOutput主要的工作是将协议编码器编码后的字节buffer,缓存起来,等待flush方法调用时,则将数据发送出去。SimpleProtocolEncoderOutput为ProtocolEncoderOutput的简单实现内部有一个buffer队列bufferQueue(Queue),用于存放write(ByteBuffer)方法,传入的字节buffer;
mergeAll方法为合并buffer队列的所有buffer数据到一个buffer;flush方法为发送buffer队列中的所有buffer,实际发送工作委托给doFlush方法待子类实现。ProtocolEncoderOutputImpl为协议编解码过滤器的内部类,ProtocolEncoderOutputImpl的doFlush,首先将会话包装成DefaultWriteFuture,将会话,写请求信息传递给NextFilter。

附:
/**
 * A default implementation of {@link WriteFuture}.
 * 
 * @author The Apache Directory Project (mina-dev@directory.apache.org)
 * @version $Rev$, $Date$
 */
public class DefaultWriteFuture extends DefaultIoFuture implements WriteFuture 




DefaultIoFuture:



  • 大小: 20.6 KB
  • 大小: 51.6 KB
0
1
分享到:
评论

相关推荐

    mina自定义编码解码器

    在Java的网络编程中,...理解Mina的过滤器机制和编码解码器接口,能够帮助开发者高效地处理网络通信中的数据转换,从而实现复杂的应用场景。通过不断地实践和优化,你可以构建出符合业务需求的高效、可靠的网络服务。

    mina框架自定义解编码器

    MINA的编码器和解编码器遵循了Filter设计模式,每个解编码器都是一个过滤器,可以在数据传递过程中进行拦截和处理。 3. **自定义解编码器的实现** 自定义解编码器需要继承MINA提供的AbstractDecoder类或其子类,并...

    mina 多路分离解码

    2. 在解码过滤器中,数据被分割成多个“消息”单元,每个消息对应一个连接。 3. 消息被传递给相应的解码器进行解码,解码器根据协议解析出有意义的信息。 4. 解码后的对象被传递到下一个过滤器,直至到达业务处理...

    Mina自定义协议简单实现

    - **添加编码器和解码器**:通过`FilterChainBuilder`创建过滤器链,添加自定义的编码器和解码器,确保数据在发送和接收时正确处理。 3. **创建Mina客户端** - **配置Connector**:使用`TcpClient`或`...

    给予mina 协议进行大数据传输

    6. **丰富的API**:MINA提供了一套完整的API,包括Filter(过滤器)机制,可以方便地对网络数据流进行拦截、修改或增强。 7. **自定义编码与解码**:如前所述,MINA支持自定义编解码器,允许开发者根据业务需求定制...

    mina编码器详解

    Mina是Apache下的一个高效、轻量级的网络通信框架,支持多种传输协议如TCP、UDP等,并提供了丰富的过滤器机制来处理复杂的网络通信任务。其中,`ProtocolCodecFilter`是Mina中用于处理数据编码与解码的核心组件之一...

    mina解码器

    在给出的代码中,`MyProtocolFactory` 实现了 `ProtocolCodecFactory` 接口,这个工厂类的作用是为MINA的过滤器链提供解码器和编码器。 `MyProtocolDecoder` 类继承自 `ProtocolDecoderAdapter`,其主要任务是将...

    mina HTTP协议实例

    4. **编码与解码**:MINA提供了ByteToMessageDecoder和MessageToByteEncoder接口,用于数据的解码和编码。在HTTP协议中,我们需要实现这两个接口来处理HTTP报文的二进制和文本转换。 5. **源码分析**:阅读MINA的...

    Mina实现RPC的例子

    4. **实现协议编解码器**:Mina的ProtocolCodecFactory用于创建协议编码器和解码器,它们将服务方法调用和响应转换成字节流在网络上传输。这一步骤需要对服务接口的方法进行序列化和反序列化。 5. **创建Client端**...

    mina自定义编码器-固定位置指定消息的长度

    在MINA中,编码器(Encoder)和解码器(Decoder)是处理数据传输的关键组件。编码器负责将应用层的数据转换为适合在网络上传输的格式,而解码器则负责将接收到的网络数据还原为应用层可以理解的格式。在某些场景下,...

    socket 与 mina 交互数据

    在实际开发中,使用Mina可以大大简化网络编程的工作,比如创建一个MinaTest项目,我们可以定义一个简单的TCP服务,使用Mina的Acceptor监听指定端口,然后创建一个解码过滤器处理客户端发送的数据。同时,客户端也...

    apache-mina源码

    6. **Protocol Buffers**:MINA提供了协议编解码机制,允许开发者自定义协议格式。这使得MINA能灵活地支持各种网络协议,如HTTP、FTP、SMTP等。 在`apache-mina-2.0.16`这个版本中,我们可以看到以下主要内容: - ...

    Apache_Mina_Server_2.0.rar_mina

    3. **丰富的API**:Mina提供了一套完整的API,包括Filter Chain(过滤器链)、Session(会话)和Protocol Codec(协议编解码器)等概念,使得开发者可以轻松地构建网络应用。 4. **过滤器机制**:Mina的过滤器链...

    Mina2中文文档

    - **编解码器**:介绍如何使用Mina提供的编解码器过滤器对网络数据进行编码和解码。 #### Chapter 10 - Executor过滤器 - **执行器**:探讨了Mina中的Executor过滤器,用于管理和调度线程,确保程序高效运行。 ##...

    apache-mina-2.0.4.rar_apache mina_mina

    1. **Filter Chain**:Mina的核心设计模式之一是过滤器链。每个连接都有一系列过滤器,它们按照顺序处理入站和出站事件。过滤器可以实现特定功能,如数据编码解码、安全验证、性能监控等。 2. **Session**:Session...

    JAVA mina 框架源码

    4. **协议编解码**:Mina提供了多种编码解码工厂,如LineDelimiter codec用于按行分割数据,或者ProtocolDecoderOutput和ProtocolEncoderInput接口,用于自定义复杂的编解码策略。 5. **线程模型**:Mina的线程模型...

    Mina断包,粘包处理(完整实例,有客户端,服务端)

    在Mina中,解决这个问题的关键在于定义正确的协议编码器和解码器。例如,你可以使用FixedLengthFrameDecoder或LineBasedFrameDecoder来确保每个接收到的数据块都能正确地组合成原始消息。 2. **粘包**: 相反,...

    Mina开发之客户端

    4. **创建和添加Protocol Codec**: 配置一个编解码器工厂,例如TCPCodecFactory,将其添加到过滤器链中。 5. **设置Event Handler**: 定义一个实现了IoHandler接口的类,处理客户端的网络事件。 6. **发送和接收...

    Apache Mina 入门Demo

    4. **协议编码和解码**:Mina提供了多种编码器和解码器,用于将用户数据转换为网络传输格式,如ByteToMessageDecoder和MessageToByteEncoder。你可以根据需要自定义这些编码器和解码器以适应特定的协议。 5. **事件...

Global site tag (gtag.js) - Google Analytics