前面我们分析了FrameDecoder的实现,我们接下来看看它的子类实现吧!
我们首先来看DelimiterBasedFrameDecoder的实现,个人认为这个类实现的真的很牛,有些变量的含义作者没有增加注释,有时候可能不容易猜到意图。首先我们来看一下这个类的成员变量:
private final ChannelBuffer[] delimiters; private final int maxFrameLength; private final boolean stripDelimiter; private final boolean failFast; private boolean discardingTooLongFrame; private int tooLongFrameLength;
- delimiters比较好理解,应该就是这个可以接受多个分割符
- maxFrameLength这个是最大帧的length
- stripDelimiter这个也很好理解,是否跳过分隔符,就是最终解码的数据里面是否包含分隔符
- failFast 为true是说发现读到的数据已经超过了maxFrameLength了,立即报TooLongFrameException,如果为false就是读完整个帧数据后再报
- discardingTooLongFrame 这个是最难理解的,含义是当前的解码器是否处于discardingTooLongFrame状态,这个参数最容易理解为是否丢弃tooLongFrame,这个是一个标志位,在构造函数里面是不能进行设置的,只能是解码器进行设置
- tooLongFrameLength这个也是一个状态属性,就是说出现了超长帧了,哪这个帧的长度到底是多少,就是这个长度,一般来说是在发现当前buffer的可读数据超过最大帧时候进行设置
好,看完这个东东后我们就来看一下它的实现:
我们就来看一下最长的这个构造函数吧:
public DelimiterBasedFrameDecoder( int maxFrameLength, boolean stripDelimiter, boolean failFast, ChannelBuffer... delimiters) { validateMaxFrameLength(maxFrameLength); if (delimiters == null) { throw new NullPointerException("delimiters"); } if (delimiters.length == 0) { throw new IllegalArgumentException("empty delimiters"); } this.delimiters = new ChannelBuffer[delimiters.length]; for (int i = 0; i < delimiters.length; i ++) { ChannelBuffer d = delimiters[i]; validateDelimiter(d); this.delimiters[i] = d.slice(d.readerIndex(), d.readableBytes()); } this.maxFrameLength = maxFrameLength; this.stripDelimiter = stripDelimiter; this.failFast = failFast; }
这个里面我们发现就是如果传递多个delimiter的时候,在这个进行了一个slice操作,没有什么特别的。
下来我们来看一下最关键的decode方法吧:
@Override protected Object decode( ChannelHandlerContext ctx, Channel channel, ChannelBuffer buffer) throws Exception { // Try all delimiters and choose the delimiter which yields the shortest frame. int minFrameLength = Integer.MAX_VALUE; ChannelBuffer minDelim = null; for (ChannelBuffer delim: delimiters) { int frameLength = indexOf(buffer, delim); if (frameLength >= 0 && frameLength < minFrameLength) { minFrameLength = frameLength; minDelim = delim; } } if (minDelim != null) { int minDelimLength = minDelim.capacity(); ChannelBuffer frame; if (discardingTooLongFrame) { // We've just finished discarding a very large frame. // Go back to the initial state. discardingTooLongFrame = false; buffer.skipBytes(minFrameLength + minDelimLength); int tooLongFrameLength = this.tooLongFrameLength; this.tooLongFrameLength = 0; if (!failFast) { fail(ctx, tooLongFrameLength); } return null; } if (minFrameLength > maxFrameLength) { // Discard read frame. buffer.skipBytes(minFrameLength + minDelimLength); fail(ctx, minFrameLength); return null; } if (stripDelimiter) { frame = buffer.readBytes(minFrameLength); buffer.skipBytes(minDelimLength); } else { frame = buffer.readBytes(minFrameLength + minDelimLength); } return frame; } else { if (!discardingTooLongFrame) { if (buffer.readableBytes() > maxFrameLength) { // Discard the content of the buffer until a delimiter is found. tooLongFrameLength = buffer.readableBytes(); buffer.skipBytes(buffer.readableBytes()); discardingTooLongFrame = true; if (failFast) { fail(ctx, tooLongFrameLength); } } } else { // Still discarding the buffer since a delimiter is not found. tooLongFrameLength += buffer.readableBytes(); buffer.skipBytes(buffer.readableBytes()); } return null; } }
我们慢慢的来看这个代码的实现,作者为了实现failfast做了很多努力。首先我们看到最开始的代码就发现,最上面实际上是尝试所有的分隔符,然后找出一个可用将帧分割最小的一个分割符出来,下面就是if和else,我们先来看if的逻辑:
- 如果找到了分割符,如果当前的解码器处于discardingTooLongFrame状态,也就是说上次解码的时候发现了超长帧,被抛弃过。首先将这个状态修改过来,标志为不是抛弃过超长帧,这个时候将整个帧丢弃掉,然后如果不是failfast状态,抛出异常,这个怎么理解呢,可以理解为上次在读取的时候发现了超长帧,但是由于设置了不立即抛出异常,而是等读完整个帧数据才抛出异常,这个时候既然发现了分隔符,该到抛出异常的时候了,最后return null表明此次分帧是失败状态。
- 如果发现此次的帧数据超过最大帧的长度,直接抛出异常
- 最后就是如果跳过分隔符,就直接跳过,负责就和分隔符和帧的实际数据一块返回
else的逻辑是当前读到的数据没有发现分隔符的情况下的逻辑,我们来看下:
- 如果发现当前的解码器不是处于discardingTooLongFrame状态,当前buffer里面的可读数据又比最大帧要大,我们就将解码器标记为discardingTooLongFrame状态,并设置这个超长帧的大小,如果是failfast状态,就立马抛出异常,也就是说我们发现了超长帧了,所以我们立马抛出异常
- 如果发现当前的解码器已经处于discardingTooLongFrame状态,我们别无他方,只能修改下tooLongFrameLength的长度,然后听天由命,等待下次解码操作
- 这个时候如果一旦发现了超长帧,都return null,含义就是说此次解码是无效的
最后我们来看一下indexOf的实现吧,这个很简单,其实思想和在字符串中找子串的思想是一致的,就不多讲解了,自己上代码:
private static int indexOf(ChannelBuffer haystack, ChannelBuffer needle) { for (int i = haystack.readerIndex(); i < haystack.writerIndex(); i ++) { int haystackIndex = i; int needleIndex; for (needleIndex = 0; needleIndex < needle.capacity(); needleIndex ++) { if (haystack.getByte(haystackIndex) != needle.getByte(needleIndex)) { break; } else { haystackIndex ++; if (haystackIndex == haystack.writerIndex() && needleIndex != needle.capacity() - 1) { return -1; } } } if (needleIndex == needle.capacity()) { // Found the needle from the haystack! return i - haystack.readerIndex(); } } return -1; }
相关推荐
一个netty的入门教程以及源码分析视频,适合刚学习的人
《Netty源码深入分析》是由美团基础架构部的闪电侠老师所分享的一系列关于Netty源码解析的视频教程。以下将根据标题、描述、标签以及部分内容等信息,对Netty及其源码进行深入剖析。 ### Netty简介 Netty是基于...
《Netty源码剖析视频》课程是一份深度探讨Netty框架源码及其实战应用的资源集合。课程分为两个主要部分,旨在帮助开发者深入理解Netty的内部机制,并通过实战项目提升其在实际开发中的应用能力。 第一部分,深入浅...
Netty 是一个高性能、异步事件驱动的网络应用程序框架,用于快速开发可维护的...在分析源码的过程中,我们通常会关注类的设计模式、线程模型、内存管理以及性能优化等方面,这对于提升网络编程和系统架构能力大有裨益。
Netty是一款高性能的网络应用程序框架,它使用Java编程语言开发,主要用于网络应用程序的快速和易于开发,支持TCP和UDP...通过对Netty源码的深入分析,可以更好地理解其工作机制,对开发高性能的网络应用有极大的帮助。
压缩包内的文件"netty源码剖析视频教程.txt"可能是课程的详细大纲或笔记,提供了对课程内容的进一步概述,包括每个章节的重点和案例分析,是学习过程中不可或缺的参考资料。通过结合视频教程和文本资料,学习者可以...
接下来,我们谈谈 Netty 的源码分析。通过阅读 Netty 源码,我们可以深入了解其设计模式和优化策略: 1. **EventLoop(事件循环)**:Netty 使用单线程的 EventLoop 实现了事件的高效分发,减少了线程切换的开销。 ...
### Netty源码剖析与NIO及Netty5各种RPC架构实战演练三部曲知识点解析 #### 一、Netty概述 Netty是一款基于Java NIO的高性能服务器端编程框架,用于快速开发可维护的网络应用程序。它简化了网络编程的复杂性,使...
Netty源码剖析+视频
本文档主要讲述了Netty5.0架构剖析和源码解读,涵盖了Netty的架构、源码分析、NIO入门等方面的知识点。 概述 JAVA 的 IO 演进是一个长期的过程,从传统的 BIO 通信到 NIO 的出现,都是为了解决通信中的问题。传统...
#### 五、Netty源码分析实战案例 1. **ChannelHandlerContext与ChannelHandlerAdaptor详解**: - 分析`ChannelHandlerContext`的生命周期及其与`ChannelHandler`之间的交互方式。 - 深入理解`...
总的来说,Netty 源码分析涉及了网络编程、并发处理、事件驱动、协议编解码等多个领域,对理解 Java 高性能网络应用开发有着重要的指导意义。通过阅读源码,我们可以更深入地了解 Netty 如何实现高效的网络通信,并...
在描述中提到的"只需要下载netty源码,再添加这些jar就可以编译通过了",这意味着你需要获取Netty的源代码仓库,通常可以从GitHub等开源平台获得。源代码包含了Netty的所有模块和组件,可以让你深入了解其内部工作...
视频分两部分 第1 章 : 第一部分、深入浅出Netty源码剖析。。 第2 章 : 第二部分、NIO+Netty5各种RPC架构实战演练
netty-3.3.1.Final-sources.jar src源码
1. **理解底层机制**:通过分析Netty的源码依赖包,可以更深入地理解其内部的工作原理和设计模式,这对于优化网络应用性能至关重要。 2. **学习优秀实践**:Netty作为一个成熟且广泛使用的项目,其代码质量和架构...
Netty 是一个高性能、异步事件驱动的网络应用程序框架,用于快速开发可维护的高性能协议服务器和客户端。在深入探讨 Netty 源码之前...通过分析源码,不仅可以提升自己的技术能力,还能为解决实际问题提供灵感和参考。
netty源码包,可以本地搭建netty源码环境,学习nio模式