我们接下来就看和业务息息相关的解码器,首先我们来看FrameDecoder,这个东西应该是所有的解码器都会实现这个,所以我们来重点看一下。
FrameDecoder产生的根源就是TCP/IP数据包的传输方式决定的,包在传输的过程中会分片和重组,
正如javadoc里面所说的:
客户端在发送的时候的序列如下:
+-----+-----+-----+
| ABC | DEF | GHI |
+-----+-----+-----+
服务器端在接受到后可能会变成下面的序列:
+----+-------+---+---+
| AB | CDEFG | H | I |
+----+-------+---+---+
FrameDecoder帮助我们将接受到的数据包整理成有意义的数据帧,例如,可以帮助我们将数据包整理成
下面的数据格式:
+-----+-----+-----+
| ABC | DEF | GHI |
+-----+-----+-----+
我们接下来就看看FrameDecoder的实现吧:
FrameDecoder是继承SimpleChannelUpstreamHandler的,我们首先来看一下messageReceived的实现:
@Override public void messageReceived( ChannelHandlerContext ctx, MessageEvent e) throws Exception { Object m = e.getMessage(); if (!(m instanceof ChannelBuffer)) { ctx.sendUpstream(e); return; } ChannelBuffer input = (ChannelBuffer) m; if (!input.readable()) { return; } ChannelBuffer cumulation = cumulation(ctx); if (cumulation.readable()) { cumulation.discardReadBytes(); cumulation.writeBytes(input); callDecode(ctx, e.getChannel(), cumulation, e.getRemoteAddress()); } else { callDecode(ctx, e.getChannel(), input, e.getRemoteAddress()); if (input.readable()) { cumulation.writeBytes(input); } } }
这个里面首先会检查input的可读性,这个比较好理解,关键是cumulation,
我们首先来看一下cumulation的实现吧:
private ChannelBuffer cumulation(ChannelHandlerContext ctx) { ChannelBuffer c = cumulation; if (c == null) { c = ChannelBuffers.dynamicBuffer( ctx.getChannel().getConfig().getBufferFactory()); cumulation = c; } return c; }
这个函数很简单,就是如果cumulation为空的时候初始化一下,如果不为空,就返回。我们得思考一下什么时候cumulation为空,什么时候不为空。我们再回过头来看一下上面的实现吧。如果cumulation可读,cumulation.discardReadBytes函数的作用是将0到readIndex之间的空间释放掉,将readIndex和writeIndex都重新标记一下。然后将读到的数据写到buffer里面。如果cumulation不可读,在调callDecode,如果发现从不可读状态到可读状态,则将读到的数据写到缓存区里面。
我们再来看callDecode的实现:
private void callDecode( ChannelHandlerContext context, Channel channel, ChannelBuffer cumulation, SocketAddress remoteAddress) throws Exception { while (cumulation.readable()) { int oldReaderIndex = cumulation.readerIndex(); Object frame = decode(context, channel, cumulation); if (frame == null) { if (oldReaderIndex == cumulation.readerIndex()) { // Seems like more data is required. // Let us wait for the next notification. break; } else { // Previous data has been discarded. // Probably it is reading on. continue; } } else if (oldReaderIndex == cumulation.readerIndex()) { throw new IllegalStateException( "decode() method must read at least one byte " + "if it returned a frame (caused by: " + getClass() + ")"); } unfoldAndFireMessageReceived(context, remoteAddress, frame); } if (!cumulation.readable()) { this.cumulation = null; } }
这个里面上面是一个循环,首先将读指针备份一下,decode方法是交个子类实现的一个抽象方这个用来实现具体数据分帧的算法,从这个里面看到如果子类没有读到一帧数据,则返回null所以下面有一个判断,是一点数据没有读呢,还是读了一点,如果一点都没有读,就不需要再检测了等下一次messageRecieved进行通知,如果发现读了一点数据,就调用下一次分帧。如果读了一帧数据就发送一个通知,unfold是针对读到的循环数据要不要打开的意思。到最后如果发现不是可读状态,
cumulation将会被设置成null。
最后来看一下cleanup的实现
private void cleanup(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { try { ChannelBuffer cumulation = this.cumulation; if (cumulation == null) { return; } else { this.cumulation = null; } if (cumulation.readable()) { // Make sure all frames are read before notifying a closed channel. callDecode(ctx, ctx.getChannel(), cumulation, null); } // Call decodeLast() finally. Please note that decodeLast() is // called even if there's nothing more to read from the buffer to // notify a user that the connection was closed explicitly. Object partialFrame = decodeLast(ctx, ctx.getChannel(), cumulation); if (partialFrame != null) { unfoldAndFireMessageReceived(ctx, null, partialFrame); } } finally { ctx.sendUpstream(e); } }
在这个里面一般来说是在socket断开的时候调用,这个时候如果发现buffer还是可读状态,还会努力的确保所有的数据已经被分帧,然后调用decodeLast
相关推荐
一个netty的入门教程以及源码分析视频,适合刚学习的人
《Netty源码深入分析》是由美团基础架构部的闪电侠老师所分享的一系列关于Netty源码解析的视频教程。以下将根据标题、描述、标签以及部分内容等信息,对Netty及其源码进行深入剖析。 ### Netty简介 Netty是基于...
《Netty源码剖析视频》课程是一份深度探讨Netty框架源码及其实战应用的资源集合。课程分为两个主要部分,旨在帮助开发者深入理解Netty的内部机制,并通过实战项目提升其在实际开发中的应用能力。 第一部分,深入浅...
Netty 是一个高性能、异步事件驱动的网络应用程序框架,用于快速开发可维护的...在分析源码的过程中,我们通常会关注类的设计模式、线程模型、内存管理以及性能优化等方面,这对于提升网络编程和系统架构能力大有裨益。
压缩包内的文件"netty源码剖析视频教程.txt"可能是课程的详细大纲或笔记,提供了对课程内容的进一步概述,包括每个章节的重点和案例分析,是学习过程中不可或缺的参考资料。通过结合视频教程和文本资料,学习者可以...
Netty是一款高性能的网络应用程序框架,它使用Java编程语言开发,主要用于网络应用程序的快速和易于开发,支持TCP和UDP...通过对Netty源码的深入分析,可以更好地理解其工作机制,对开发高性能的网络应用有极大的帮助。
接下来,我们谈谈 Netty 的源码分析。通过阅读 Netty 源码,我们可以深入了解其设计模式和优化策略: 1. **EventLoop(事件循环)**:Netty 使用单线程的 EventLoop 实现了事件的高效分发,减少了线程切换的开销。 ...
尤其是在RPC架构领域,Netty凭借其强大的功能和灵活的设计成为了构建分布式系统的首选工具之一。希望本教程能够帮助大家更好地理解和运用Netty进行项目实战。 以上就是对Netty源码剖析及NIO与Netty5在RPC架构中的...
Netty源码剖析+视频
本文档主要讲述了Netty5.0架构剖析和源码解读,涵盖了Netty的架构、源码分析、NIO入门等方面的知识点。 概述 JAVA 的 IO 演进是一个长期的过程,从传统的 BIO 通信到 NIO 的出现,都是为了解决通信中的问题。传统...
#### 五、Netty源码分析实战案例 1. **ChannelHandlerContext与ChannelHandlerAdaptor详解**: - 分析`ChannelHandlerContext`的生命周期及其与`ChannelHandler`之间的交互方式。 - 深入理解`...
总的来说,Netty 源码分析涉及了网络编程、并发处理、事件驱动、协议编解码等多个领域,对理解 Java 高性能网络应用开发有着重要的指导意义。通过阅读源码,我们可以更深入地了解 Netty 如何实现高效的网络通信,并...
在描述中提到的"只需要下载netty源码,再添加这些jar就可以编译通过了",这意味着你需要获取Netty的源代码仓库,通常可以从GitHub等开源平台获得。源代码包含了Netty的所有模块和组件,可以让你深入了解其内部工作...
netty-3.3.1.Final-sources.jar src源码
视频分两部分 第1 章 : 第一部分、深入浅出Netty源码剖析。。 第2 章 : 第二部分、NIO+Netty5各种RPC架构实战演练
1. **理解底层机制**:通过分析Netty的源码依赖包,可以更深入地理解其内部的工作原理和设计模式,这对于优化网络应用性能至关重要。 2. **学习优秀实践**:Netty作为一个成熟且广泛使用的项目,其代码质量和架构...
Netty 是一个高性能、异步事件驱动的网络应用程序框架,用于快速开发可维护的高性能协议服务器和客户端。在深入探讨 Netty 源码之前...通过分析源码,不仅可以提升自己的技术能力,还能为解决实际问题提供灵感和参考。
netty源码包,可以本地搭建netty源码环境,学习nio模式