posts - 5, comments - 0, trackbacks - 0, articles - 0
  BlogJava :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理
  使用过mina的同学应该都遇到到过,在解码时少包、多包的问题,查阅了很多资料还是迷迷糊糊的,经过

不懈努力,终于解决了。原来解决方法是那样的简单。废话少说,请看列子。
  
   另外建了一个交流群:19702042,大家可以在线交流

   问题:我发送的是xml字符串数据,在发送数据后,接收方在解码的时候可能接到1条,也可能是多条,还

可能是半条或一条半,解决方法就是使用CumulativeProtocolDecoder

   首先,在编码的时候要把前4位设成标志位,标志消息内容的长度。里面的重点是doDecode的返回值,一

定要继承CumulativeProtocolDecoder 哦。

   清看decode的写法:
Java代码 复制代码 收藏代码
  1. public class AsResponseDecoder extends CumulativeProtocolDecoder {   
  2.     private static Logger LOG = LoggerFactory.getLogger(AsResponseDecoder.class);   
  3.     private final Charset charset;   
  4.        
  5.     public AsResponseDecoder(Charset charset){   
  6.         this.charset = charset;   
  7.     }   
  8.        
  9.   
  10.     /**  
  11.      * 这个方法的返回值是重点:  
  12.      * 1、当内容刚好时,返回false,告知父类接收下一批内容  
  13.      * 2、内容不够时需要下一批发过来的内容,此时返回false,这样父类  
  14.  
  15. CumulativeProtocolDecoder  
  16.      *    会将内容放进IoSession中,等下次来数据后就自动拼装再交给本类的doDecode  
  17.      * 3、当内容多时,返回true,因为需要再将本批数据进行读取,父类会将剩余的数据再次推送本  
  18.  
  19. 类的doDecode  
  20.      */  
  21.     public boolean doDecode(IoSession session, IoBuffer in,   
  22.             ProtocolDecoderOutput out) throws Exception {   
  23.            
  24.         CharsetDecoder cd = charset.newDecoder();   
  25.         if(in.remaining() > 0){//有数据时,读取4字节判断消息长度   
  26.             byte [] sizeBytes = new byte[4];   
  27.             in.mark();//标记当前位置,以便reset   
  28.             in.get(sizeBytes);//读取前4字节   
  29.                         //NumberUtil是自己写的一个int转byte[]的一个工具类   
  30.             int size = NumberUtil.byteArrayToInt(sizeBytes);   
  31.             //如果消息内容的长度不够则直接返回true   
  32.             if(size > in.remaining()){//如果消息内容不够,则重置,相当于不读取size   
  33.                 in.reset();   
  34.                 return false;//接收新数据,以拼凑成完整数据   
  35.             } else{   
  36.                 byte[] bytes = new byte[size];    
  37.                 in.get(bytes, 0, size);   
  38.                 String xmlStr = new String(bytes,"UTF-8");   
  39.                 System.out.println("------------"+xmlStr);   
  40.                 if(null != xmlStr && xmlStr.length() > 0){   
  41.                     AsResponse resCmd = new AsResponse();   
  42.                     AsXmlPacker.parse(resCmd, xmlStr);   
  43.                     if(resCmd != null){   
  44.                         out.write(resCmd);   
  45.                     }   
  46.                 }   
  47.                 if(in.remaining() > 0){//如果读取内容后还粘了包,就让父类再给俺   
  48.   
  49. 一次,进行下一次解析   
  50.                     return true;   
  51.                 }   
  52.             }   
  53.         }   
  54.         return false;//处理成功,让父类进行接收下个包   
  55.     }   
  56.   
  57.   
  58. }  

下面附上Encode类
Java代码 复制代码 收藏代码
  1. public class AsResponseEncoder extends ProtocolEncoderAdapter {   
  2.     private final Charset charset;   
  3.        
  4.     public AsResponseEncoder(Charset charset){   
  5.         this.charset = charset;   
  6.     }   
  7.        
  8.     public void encode(IoSession session, Object message,   
  9.         ProtocolEncoderOutput out) throws Exception {   
  10.         CharsetEncoder ce = charset.newEncoder();   
  11.         IoBuffer buffer = IoBuffer.allocate(100).setAutoExpand(true);   
  12.            
  13.         AsResponse respCmd = (AsResponse) message;   
  14.            
  15.         String xml = AsXmlPacker.pack(respCmd);//将对象转成xml   
  16.         byte[] bytes = xml.getBytes();   
  17.         byte[] sizeBytes = NumberUtil.intToByteArray(bytes.length);   
  18.            
  19.         buffer.put(sizeBytes);//将前4位设置成数据体的字节长度   
  20.         buffer.put(bytes);//消息内容   
  21.         buffer.flip();   
  22.         out.write(buffer);   
  23.     }   
  24.   
  25.   
  26. }  

    JDK   ByteBuffer

     

    属性:

    Mark

    上次position的快照

    Position

    当前读写索引未知

    Limit

    缓冲区限制

    Capacity

    缓冲区能力

    Offset

    偏移量

     

    说明:

    • Position(Mark)<=limit<=capacity
    • position==limit时就没有字节可读写了
    • 每次getput都将增加position
    • 重置mark就是设置mark=-1

     

     

    方法:

    Limit(int)

    如果position>limit, position = limit,如果mark>limit, 重置mark

    Mark()

    取当前的position的快照标记mark

    Reset()

    恢复position到先前标记的mark

    Clear()

    limit=capacity , position=0,重置mark,但是不清空数据,为了从头开始put做准备,其实就是清空数据,因为你put就覆盖了原来的数据

    Rewind()

    position=0,重置mark,一系列写操作后,为了从头开始get做准备,和clear()有用途上的区别,他大部分是用来从头开始读取,而clear是大部分用来重头开始填充,就是清理的意思

    Flip()

    limit=position , position=0,重置mask,为了将buf写出做好准备,一般是结束buf操作,将buf写入输出流时调用,这个必须要调用,否则极有可能position!=limit,导致position后面没有数据,每次写入数据到输出流时,必须确保position=limit

    Remaining()

    返回limit-position,返回缓冲器中的剩余字节

    Wrap(byte[])

    组装到新的buffercapacity=limit=byte[].lengthposition=0 重置mark

    Slice()

    分割缓冲器,将remaining的空间形成一个新的buffer,新的position=0limit=capacity=remaining,重置mark,和主缓冲区内容共享,其它都独立

    Duplicate()

    复制缓冲区,内容共享,其它都独立

    asReadOnlyBuffer()

    和duplicate一样,只是不可写

    Compact()

    positionlimit之间的字节移到最前面,position=limit-position,这就是这里的压缩的意思,一般是结束buf操作,将buf写入输出流时调用

    Position(int)

    position=newPosition,如果position<mark,重置mark

    Remaining()

    返回positionlimit之间的字节数

 

 

JDK ByteBuffer

Mina IoBuffer

动态扩展capacity

支持String读写

线程安全

可主动释放缓冲区占用内存


只有注册用户登录后才能发表评论。


网站导航: