Mina 粘包断包解码 CumulativeProtocolDecoder 源码解读
来源:互联网 发布:数据库概论第四版 编辑:程序博客网 时间:2024/05/16 07:47
这个解码器就是处理粘包和断包的。主要思路:多个包顺序处理。直到全部处理完毕。如果不够解包的数据,则存储到会话中,下次再收到数据合并再处理。
看完源代码后,对自定义的子类的实现方法就有方向了。具体怎么解码自定义包和业务逻辑相关,不解释。
public abstract class CumulativeProtocolDecoder extends ProtocolDecoderAdapter { private final AttributeKey BUFFER = new AttributeKey(getClass(), "buffer"); /** * Creates a new instance. */ protected CumulativeProtocolDecoder() { // Do nothing } /** * Cumulates content of <tt>in</tt> into internal buffer and forwards * decoding request to {@link #doDecode(IoSession, IoBuffer, ProtocolDecoderOutput)}. * <tt>doDecode()</tt> is invoked repeatedly until it returns <tt>false</tt> * and the cumulative buffer is compacted after decoding ends. * * @throws IllegalStateException if your <tt>doDecode()</tt> returned * <tt>true</tt> not consuming the cumulative buffer. * 累积型处理解码,此处理已包含粘包和断包的情况。 */ public void decode(IoSession session, IoBuffer in, ProtocolDecoderOutput out) throws Exception { /** * 没有断包设置时走这块代码。 * 此时认为此包中没有断包的情况,比如同时N个包。一直处理直到解码不成功直接退出,不管还有没有包数据。 * NioSocketSession设置的变量为true,其他session实现类不清楚。也就是不走这块。继续看下面代码吧。 * */ if (!session.getTransportMetadata().hasFragmentation()) { while (in.hasRemaining()) { if (!doDecode(session, in, out)) { break; } } return; } boolean usingSessionBuffer = true;//使用了上次session中存储的剩余包数据。默认为true IoBuffer buf = (IoBuffer) session.getAttribute(BUFFER);//尝试读取剩余包数据。 // If we have a session buffer, append data to that; otherwise // use the buffer read from the network directly. if (buf != null) {//有上次的剩余包 boolean appended = false;//是否添加了这次的包 // Make sure that the buffer is auto-expanded. if (buf.isAutoExpand()) {//如果剩余包为自动扩展的,那好,把这次的包装到后面,并置为标识为true. try { buf.put(in); appended = true; } catch (IllegalStateException e) { // A user called derivation method (e.g. slice()), // which disables auto-expansion of the parent buffer. } catch (IndexOutOfBoundsException e) { // A user disabled auto-expansion. } } if (appended) { buf.flip();//装到后面后,要对整个包进行重置。好让下面的处理从头开始处理此包。 } else { // Reallocate the buffer if append operation failed due to // derivation or disabled auto-expansion. /** * 如果剩余包不是自动扩展的,我现在装不下,那只好 把我和这次的新包,一起按照顺序装到一个新的大包里。这个新包可是自动扩展的。 * */ 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; // Update the session attribute. session.setAttribute(BUFFER, buf);//弄好后,先将这个新包存起来。 } } else {//没有剩余包,直接使用这次的包,并将其标识置为false。 buf = in; usingSessionBuffer = false; } /** * 循环处理这个包,直到不够解码时,或此包已读完。 * */ for (;;) { int oldPos = buf.position();//记录下这次处理的初始位置,看看后面的程序到底有没有动过我。 /** * 这个方法要真正解码处理。原则:1.读这个大包,如果包中的数据已满足可以解出自定义对象,你就先解出此对象,并通过out.write先存起来。然后返回true告诉这里,我再检查下这个包还有没有数据,如果有再调用此方法再解码。 * 2.如果这个包中数据不够解码的了,你也别动后面的数据了,直接返回false到这里。然后这个循就退出了。因为没有可用的数据了,这次的工作已经结束,然后收拾收拾场地,该存的存起来。等下次了。 * 总之:这个方法就是你看下这个包,要是够你用的,你就用,然后返回true。如果这次不够用,你最好什么也别动,或者动了也要给我弄好。返回false。 不然咱们没有下回了。 * */ boolean decoded = doDecode(session, buf, out); if (decoded) {//这次成功解码。 if (buf.position() == oldPos) {//如果没有使用这个包的数据,为什么要返回true。你骗我。这时应该返回false. throw new IllegalStateException("doDecode() can't return true when buffer is not consumed."); } if (!buf.hasRemaining()) {//此包已使用完。退出。 break; } } else {//没有成功解码,可能有剩余啊,直接中止。再循环也没意义,因为这会的材料就是不够。 break; } } // if there is any data left that cannot be decoded, we store // it in a buffer in the session and next time this decoder is // invoked the session buffer gets appended to /** * 要是还有剩余就存起来,下次再用,如果没有了。把会话里残留的都清掉。 * */ if (buf.hasRemaining()) { //这个&&的两个条件是同时成立的。不会出现第一个为true,而第二个条件为false。是由上面的代码保证的。各位不要太纠结这块。写这个的大神已考虑到了。 if (usingSessionBuffer && buf.isAutoExpand()) {//已经存到会话里了,就不存了,不过要看下如果这个包是自动扩展的。要压缩下容量,不然这个包容量太大,而里面又没装多少东西。也好省点内存哈。 buf.compact(); } else { storeRemainingInSession(buf, session);//直接存到会话里。 } } else { if (usingSessionBuffer) {//如果以前有会话残留,就清理掉。 removeSessionBuffer(session); } } } /** * Implement this method to consume the specified cumulative buffer and * decode its content into message(s). * * @param in the cumulative buffer * @return <tt>true</tt> if and only if there's more to decode in the buffer * and you want to have <tt>doDecode</tt> method invoked again. * Return <tt>false</tt> if remaining data is not enough to decode, * then this method will be invoked again when more data is cumulated. * @throws Exception if cannot decode <tt>in</tt>. */ protected abstract boolean doDecode(IoSession session, IoBuffer in, ProtocolDecoderOutput out) throws Exception; /** * Releases the cumulative buffer used by the specified <tt>session</tt>. * Please don't forget to call <tt>super.dispose( session )</tt> when * you override this method. */ @Override public void dispose(IoSession session) throws Exception { removeSessionBuffer(session); } private void removeSessionBuffer(IoSession session) { session.removeAttribute(BUFFER); } private void storeRemainingInSession(IoBuffer buf, IoSession session) { final IoBuffer remainingBuf = IoBuffer.allocate(buf.capacity()).setAutoExpand(true); remainingBuf.order(buf.order()); remainingBuf.put(buf); session.setAttribute(BUFFER, remainingBuf); }}
0 0
- Mina 粘包断包解码 CumulativeProtocolDecoder 源码解读
- MINA源码分析---CumulativeProtocolDecoder协议解码器
- MINA源码解读(二)
- MINA源码解读(一)
- Mina 心跳KeepAliveFilter 源码解读
- Apache Mina CumulativeProtocolDecoder 内部函数说明
- mina框架CumulativeProtocolDecoder.doDecode方法浅析
- MINA源码分析---base64编码和解码
- mina源码阅读之编码与解码
- MINA源码分析---协议解码输出接口ProtocolDecoderOutput及其实现
- MINA源码分析---协议编码解码过滤器ProtocolCodecFilter
- Mina源码阅读笔记(一)-整体解读
- Mina源码阅读笔记(一)-整体解读
- MINA 协议解码过滤器
- mina自定义编解码
- mina源码
- MINA框架中的编码解码以及对粘包断包的处理
- 深入解析Apache Mina源码(4)——Mina编解码以及对粘包和断包的处理
- 在英特尔® 凌动™ 平台上进行 Android* 应用开发和优化
- 永久修改redhat的default route
- leetcode题目:Copy List with Random Pointer
- VC++ 下多媒体高精度定时器timeSetEvent
- iPhone手机壳能长途遥控:内置可拆卸摄像头
- Mina 粘包断包解码 CumulativeProtocolDecoder 源码解读
- Oracle 11g 通过间隔分区实现按月创建表分区
- C#:winform项目在win7,xp32位和64位都能运行
- dependencies 和 dependencyManagement 的区别
- Chrome浏览器修改页面背景色
- 服务器XE,D7安装控件情况
- 溜走的昨天
- 发短信
- WPF 学习笔记-设置属性使窗口不可改变大小