异步网络编程框架-Netty概念介绍

 

在上节中,我们通过helloworldclientserver端程序,成功运行了HelloWorld。看到输出很兴奋,有木有?但是对于demo中的各种概念都要问下,这个是什么意思?这个为什么要这么写?本节我们来学习demo教程提到关于Netty的几个概念。

  首先是Bootstrap,我们先来看下bootstrap的类图,并且浏览下官方定义:

A helper class which initialize a Channel. This class provides the common data structure for its subclasses which actually initialize Channel’s and their child Channel’s using the common data structure. Please refer to ClientBootstrap, ServerBootstrap, and ConnectionlessBootstrap for client side, server-side, and connectionless (e.g. UDP) channel initialization respectively.

Bootstrap:初始化Channel的帮助类,包括初始化连接的基本数据结构,包括ChannelFactoryChannelPipelineChannelPipelineFactory,以及保存Server或者Client端配置的options。其中ServerBootstrapConnectionlessBootstrapServer端创建,ClientBootstrapClient端创建,顾名思义,ConnectionlessBootstrapServer端创建的UDP/IP应用。TCPUDP的区别就不说了,根据自己应用的类别,选择合适的Bootstrap

这个bootstrap就是个工具类,对于clientserver端来说,连接完成后就Ok,至于具体的连接处理,连接关闭等都要靠具体的Channel来处理。Bootstrap的使用就和上节中的例程一样,没有更复杂的操作;准确的应该说和bootstrap这个类没有太大的关系,都是后面提及的channelpipeline的操作。

ChannelBuffer-类图及官方定义:

A random and sequential accessible sequence of zero or more bytes (octets). This interface provides an abstract view for one or more primitive byte arrays (byte[]) and NIO Buffers.

ChanelBufferNetty中的核心类,但是按照文档说明,ChannelBuffer就是把byte ArraysNIO byteBuffer包装一下,更方便的操作byte,毕竟在Channel中传输的是byte

ChannelBuffer操作和NIO里面的ByteBuffer操作有些不一致的地方,更准确的说,ChannelBuffer定义了一套Buffer的操作,并且在应用中严格遵守规则来操作Buffer。下面我们看下Buffer的操作:

  1. Buffer创建:建议使用ChannelBuffers来初始化,对于具体Buffer的构造函数不建议使用。如果没有指定创建Buffer的形式,默认创建HeapChannelBuffer,否则按照你指定的方式创建。
  2. 支持随机索引读取。
  3. Buffer操作:ChannelBuffer实际上是按照readerIndexwriterIndex来将Buffer区分成DescardableBytesReadableByteWritableByte,所有的读写取操作同时更新的是readerIndexwriterIndex。这些个关系可以仔细看下文档,熟悉了这些操作,感觉比NIObuffer操作起来要方便。
  4. 注意Bufferclearreset操作,clear操作并不会清空Buffer数据,只是重置readerIndexwriterIndexreset操作也是同样,只是重置,不对buffer里面的数据操作。所以对于Buffer的访问,只能通过readerIndexwriterIndex来访问,所以,尽量用逻辑意义去访问Bufferclear之后,就不要再读取Buffer里面的数据了,尽管数据存在,但是从逻辑意义上,你已经删除这些数据了(物理数据依然存在)。
  5. 上一章节中提到了ChannelBufferZero-Copy操作,这个为什么能够提高性能,怎么实现?duplicateslice操作会返回独立的readerIndexwriterIndexBuffer里面的数据么有改变;该Buffer和原Buffer共用一块数据,但是可以独立操作,如果你没有修改buffer数据的意向,只是查找或者进行逻辑判断,这个duplicateslice操作正和你意。这个能从很大意义上减小内存拷贝操作,如果你确实想复制一份buffers数据,请用copy函数,这个操作会返回一个原Buffer的拷贝。所用使用sliceduplicatecopy函数之前,请确认自己的操作意向,尽可能利用buffer特性,提高性能。
  6. Buffer里面有这么两个参数markedReaderIndexmarkedWriterIndex,各位看官可以看下这两个参数有什么用?再提醒下,BuffertoString方法和Java本身的toString方法不一致。

channelBuffer的具体实现类图

ChannelBuffer有这么多种实现,他们之间有什么区别呢?其实在上面已经有提及,如果想具体了解下,可以看下这些Bufferduplicateslicecopy操作。这个上面有个ByteBufferBackedChannelBuffer,这个BufferNIOBuffer最为相似,不过也遵循readerIndexwriterIndex的限制。

Channel:Netty的核心类

这个channelNetty的核心,所有关于连接的东西,都在这个channel类中有体现:包括channel statechannel configurationchannel IO operation supportedchannel IO event and request(有channelPipeline负责处理)。接收到请求后,根据channel状态,读取channel配置,查询当前操作channel是否支持,再送往channelPipeline处理,处理完之后送回。

这个类是很重要,理解该类的执行流程能够理解request的执行过程。

 

ChannelFactory:类图

ChannelFactory:顾名思义,用来产生Channel。里面有三个属性:bossExecutorworkerExecutorsink。这个sink的产生跟bossExecutorworkerExecutor有关系,默认线程数boss=1worker=2*processor;是用来具体执行请求过程,重点关注eventSunk函数。关于执行流程会有额外分析。

 

ChannelEvent:类图

终于到ChannelEvent分析了:Nettyevent-driven操作,这个Event就很关键了。Event分为ChannelStateEventChildChannelStateEventExceptionEventIdleStateEventMessageEventWriteCompletionEvent。这些Event各有操作,先看下ChannelStateEvent

UpstreamChannelStateEventDownstreamChannelStateEvent,这两个操作是用来处理channelState上行事件和下行下行事件的。其实就是触发在channel state状态改变时触发,包括openbindconnectdisconnectunbindclosed等状态。另外channelinterops变化时也会触发该事件。几乎所有的操作都会有触发该Event,以激活后面SimpleChannelUpstreamHandlerSimpleChannelDownstreamHandler操作。

下面看下MessageEvent

MessageEvent比较简单,连接建立后,对于数据流的交互会产生上行的UpstreamMessageEvent和下行的DownstreamMessageEvent。这个事件会相应触发handlermessageReceivedwriteRequest。具体的逻辑就在自己定义的handler里面实现。

 

ChannelHandler:类图

ChannelHandler包括ChannelUpstreamHandlerChannelDownstreamHandler,这两个handler是系统预定义好的,用来处理一系列上行和下行数据流程的接口。根据自己的需要,覆盖掉这两个handler里面的方法,就可以实现自己的逻辑了。其实不用这么复杂,真正需要实现的是实现了这两个接口的SimpleChannelUpstreamHandlerSimpleChannelDownstreamHandler

 

ChannelPipeline:类图

ChannelPipeline是具体进行数据的流程的;包括从对象、字符串到二进制的变化,以及逻辑的处理。可以说,ChannelPipeline才是我们真正关心的核心逻辑。编写新的handler,你要考虑使用的协议类型、协议解析、Object到二进制的转换和相反的操作,最后再关心我们自己的业务处理,Serverclient端的协议处理要一致。这一连串都没有问题的话,启动Serverclient端就可以通信了。简单吧,其实想考虑这些内容,还是有难度的。

 

在我们上一节的demo教程中,Server端和client端都使用了DelimiterBasedFrameDecoderStringEncoderStringDecoder和我自己的业务逻辑handler,就能保证Server和Client端的通信啦;这三个Handler合并在一起,其实相当于Telnet通信协议。

说到这里,其实已经很简单了, 你有没有对Netty有进一步的了解了吗?

 

我们下一节见

 

 

 

 

 

 

 

猜你喜欢

转载自isilic.iteye.com/blog/1717683