apache-mina-2.07源码笔记4-codec

 1. CumulativeProtocolDecoder
      A  {@link  ProtocolDecoder} that cumulates the content of received buffers to a cumulative buffer to help users implement decoders.If the received  {@link  IoBuffer} is only a part of a message.decoders should cumulate received buffers to make a message complete or to postpone decoding until more buffers arrive.
     即解决'
粘包' ->即一次接收数据不能完全体现一个完整的消息数据->通过应用层数据协议,如协议中通过4字节描述消息大小或以结束符.

2.CumulativeProtocolDecoder#decode实现
  /**
    * 1.缓存decode中的IoBuffer in至session的attribute
    * 2.循环调用doDecode方法直到其返回false
    * 3.解码结束后缓存的buffer->压缩
    
*/

    
public   void  decode(IoSession session, IoBuffer in, ProtocolDecoderOutput out)  throws  Exception  {
       
// 判断传输层是否存在消息分片,如果不分片则直接doDecode.(可参考TCP/IP详解)
        if (!session.getTransportMetadata().hasFragmentation()) {
            
while (in.hasRemaining()) {
                
if (!doDecode(session, in, out)) {
                    
break;
                }

            }


            
return;
        }


        
boolean usingSessionBuffer = true;
        IoBuffer buf 
= (IoBuffer) session.getAttribute(BUFFER);
        
// 如果session中有BUFFER这个attribute则直接执行追加,否则直接用网络层读到的buffer
        if (buf != null{
            
boolean appended = false;
            
// Make sure that the buffer is auto-expanded.
            if (buf.isAutoExpand()) {
                
try {
                    buf.put(in);
                    appended 
= true;
                }
 catch (IllegalStateException e) {
                    
// 可能调用了类似slice的方法,会使父缓冲区的自动扩展属性失效(1.可参考AbstractIoBuffer#recapacityAllowed 2.可参考IoBuffer的实现)
                }
 catch (IndexOutOfBoundsException e) {
                    
// 取消了自动扩展属性(可参考IoBuffer实现)
                }

            }


            
if (appended) {
    
// 追加成功的话,直接flip
                buf.flip();
            }
 else {
     
// 因为用了派生的方法(父子缓冲区)如slice或取消了自动扩展而导致追加失败->重新分配一个Buffer
                buf.flip();
                IoBuffer newBuf 
= IoBuffer.allocate(buf.remaining() + in.remaining()).setAutoExpand(true);
                newBuf.order(buf.order());
                newBuf.put(buf);
                newBuf.put(in);
                newBuf.flip();
                buf 
= newBuf;

                
// 更新session属性
                session.setAttribute(BUFFER, buf);
            }

        }
 else {
    
// 此else表示session无BUFFER属性,直接赋值
            buf = in;
            usingSessionBuffer 
= false;
        }


        
// 无限循环直到break 1.doDecode返回false 2.doDecode返回true且buf已无数据 3.异常
        for (;;) {
            
int oldPos = buf.position();
            
boolean decoded = doDecode(session, buf, out);
            
if (decoded) {
                
if (buf.position() == oldPos) {
                    
throw new IllegalStateException("doDecode() can't return true when buffer is not consumed.");
                }


                
if (!buf.hasRemaining()) {
                    
break;
                }

            }
 else {
                
break;
            }

        }


        
// 如果经过decode,buffer依然有剩余数据则存储到session->这样下次decode的时候就可以从session取出buffer并执行追加了
        if (buf.hasRemaining()) {
            
if (usingSessionBuffer && buf.isAutoExpand()) {
       
// 压缩
                buf.compact();
            }
 else {
                storeRemainingInSession(buf, session);
            }

        }
 else {
            
if (usingSessionBuffer) {
                removeSessionBuffer(session);
            }

        }

    }

            注.
                    1.doDecode在消息非完整的时候返回false. 
                    2.如果doDecode成功解码出一条完整消息则返回true->如果此时buffer中依然有剩余数据则继续执行for->doDecode->直到buffer中的数据不足以解码出一条成功消息返回false.或者恰恰有n条完整的消息->从for跳出.

3.CumulativeProtocolDecoder  example
     /**
      * 解码以CRLF(回车换行)作为结束符的消息
              
*/

    
public   class  CrLfTerminatedCommandLineDecoder
          
extends  CumulativeProtocolDecoder  {
 
     
private Command parseCommand(IoBuffer in) {
    
// 实现将二进制byte[]转为业务逻辑消息对象Command
      }


   
// 只需实现doDecode方法即可
    protected boolean doDecode(
             IoSession session, IoBuffer in, ProtocolDecoderOutput out)
              
throws Exception {

        
// 初始位置
          int start = in.position();
 
          
// 查找'\r\n'标记
          byte previous = 0;
         
while (in.hasRemaining()) {
             
byte current = in.get();
 
              
// 找到了\r\n
              if (previous == '\r' && current == '\n'{
                 
// Remember the current position and limit.
                  int position = in.position();
                
int limit = in.limit();
                
try {
                      in.position(start);
                    in.limit(position);
//设置当前的位置为limit

           
// position和limit之间是一个完整的CRLF消息
                    out.write(parseCommand(in.slice()));//调用slice方法获得positon和limit之间的子缓冲区->调用write方法加入消息队列(因为网络层一个包可能有多个完整消息)->后经调用flush(遍历消息队列的消息)->nextFilter.messageReceived
filter
                  }
 finally {
                     
// 设置position为解码后的position.limit设置为旧的limit
                     in.position(position);
                    in.limit(limit);
                  }


    
// 直接返回true.因为在父类的decode方法中doDecode是循环执行的直到不再有完整的消息返回false.
               return true;
           }

 
            previous 
= current;
         }

 
          
// 没有找到\r\n,则重置position并返回false.使得父类decode->for跳出break.
          in.position(start);
 
          
return false;
      }

  }

 4. DemuxingProtocolDecoder
    
 1.public class DemuxingProtocolDecoder  extends CumulativeProtocolDecoder
     2.这是一个复合的decoder-> 多路复用- >找到一个合适的MessageDecoder.(不同的消息协议)

     3.其 doDecode 实现为迭代候选的 MessageDecoder 列表->调用MessageDecoder# decodable 方法->如果解码结果为MessageDecoderResult#NOT_OK,则从候选列表移除;如果解码结果为MessageDecoderResult#NEED_DATA,则保留该候选decoder并在更多数据到达的时候会再次调用decodable;如果返回结果为MessageDecoderResult#OK,则表明找到了正确的decoder;如果没有剩下任何的候选decoder,则抛出异常.

    4.doDecode源码
       protected   boolean  doDecode(IoSession session, IoBuffer in, ProtocolDecoderOutput out)  throws  Exception  {
              
// 从Session中获取一个State.State包含一个MessageDecoder数组以及一个当前的decoder
            State state = getState(session);

           
// 如果当前decoder为空
            if (state.currentDecoder == null{
                MessageDecoder[] decoders 
= state.decoders;
                
int undecodables = 0;
        
        
// 遍历decoder候选列表
                for (int i = decoders.length - 1; i >= 0; i--{
                    MessageDecoder decoder 
= decoders[i];
                    
int limit = in.limit();
                    
int pos = in.position();

                    MessageDecoderResult result;

                    
try {
                 
// 执行decodable方法并返回result(decodable方法是检查特定的buffer是否可以decoder解码)
                        result = decoder.decodable(session, in);
                    }
 finally {
              
// 一定要重置回旧的position和limit
                        in.position(pos);
                        in.limit(limit);
                    }


                    
if (result == MessageDecoder.OK) {
              
// 如果返回结果为OK,则设置为state的当前decoder并break
                        state.currentDecoder = decoder;
                        
break;
                    }
 else if (result == MessageDecoder.NOT_OK) {
              
// 如果返回结果为NOT_OK,则记录undecodables数目++
                        undecodables++;
                    }
 else if (result != MessageDecoder.NEED_DATA) {
               
// 如果结果都不是,即也不是NEED_DATA,则直接抛出异常
                        throw new IllegalStateException("Unexpected decode result (see your decodable()): " + result);
                    }

                }


        
// 如果没有找到合适的decoder,则抛出异常
                if (undecodables == decoders.length) {
                    
// Throw an exception if all decoders cannot decode data.
                    String dump = in.getHexDump();
                    in.position(in.limit()); 
// 跳过这段数据
                    ProtocolDecoderException e = new ProtocolDecoderException("No appropriate message decoder: " + dump);
                    e.setHexdump(dump);
                    
throw e;
                }

        
        
// 迭代结束,如果还没有找到合适的decoder则表示可能需要更多的数据->所以返回false->跳出父类的for-dodecode循环
                if (state.currentDecoder == null{
                    
// Decoder is not determined yet (i.e. we need more data)
                    return false;
                }

            }


           
// 这里表示已找到合适的decoder,调用decode方法进行解码二进制或者特定的协议数据为更高业务层的消息对象
            try {
                MessageDecoderResult result 
= state.currentDecoder.decode(session, in, out);
                
if (result == MessageDecoder.OK) {
           
// 重置为null
                    state.currentDecoder = null;
                    
return true;
                }
 else if (result == MessageDecoder.NEED_DATA) {
                    
return false;
                }
 else if (result == MessageDecoder.NOT_OK) {
                    state.currentDecoder 
= null;
                    
throw new ProtocolDecoderException("Message decoder returned NOT_OK.");
                }
 else {
                    state.currentDecoder 
= null;
                    
throw new IllegalStateException("Unexpected decode result (see your decode()): " + result);
                }

            }
 catch (Exception e) {
                state.currentDecoder 
= null;
                
throw e;
            }

        }

5.一个特定消息协议的编解码的例子, {@link org.apache.mina.example.sumup}
    1.AbstractMessageEncoder
     /**
     * 1.编码消息头,消息体编码由子类实现.
     * 2.AbstractMessage中只有一个sequence字段
     
*/

    
public   abstract   class  AbstractMessageEncoder < extends  AbstractMessage >   implements  MessageEncoder < T >   {
       
// 类型字段
        private final int type;

        
protected AbstractMessageEncoder(int type) {
            
this.type = type;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值