-
Netty,一个构建高度可伸缩的、异步的、事件驱动的网络编程应用的工具包。
-
Netty是一款异步的事件驱动的网络应用程序框架,支持快速地开发可维护的高性能的面向协议的服务器和客户端。
-
阻塞IO
-
非阻塞IO(NIO)(NON-Blocking IO):通过使用选择器轮询的方式
-
Netty的核心组件:一、Channel;二、回调;三、Future;四、事件和ChannelHandler。
-
Channel代表一个到实体(如一个硬件设备、一个文件、一个网络套接字或者一个能够执行一个或者多个不同的I/O操作的程序组件)的开放连接,如读操作和写操作。
-
JDK内置的Future会阻塞,Netty提供了自己的实现——ChannelFuture。ChannelFuture可以注册一个或者多个ChannelFutureListener实例,用于回调。
-
ChannelHandler的实现负责接收并响应事件通知。
-
针对不同类型的事件来调用ChannelHandler;应用程序通过实现或者扩展Channelhandler来挂钩到事件的生命周期,并且提供自定义的应用程序逻辑;ChannelHandler有助于保持业务逻辑和网络处理代码的分离。
-
ChannelHandler
的方法是由网络事件驱动(触发)的。 -
每一个Channel被创建时会被分配它所专属的ChannelPipeline,ChannelPipeline是ChannelHandler的链表,按添加顺序执行处理逻辑。
-
当ChannelHandler被添加到ChannelPipeline时,它将会被分配一个ChannelHandlerContext,其代表了ChannelHandler和ChannelPipeline之间的绑定。虽然这个对象可以被用于获取底层的Channel,但是它主要被用于写出站数据。
-
当通过Netty发送或者接收一个消息的时候,就会发生一次数据转换。入站消息会被解码,也就是说,从字节转换为另一种格式,比如java对象;如果是出站,则会被编码为字节。
-
Netty的Channel是线程安全的,如果多个线程都在向它写数据,消息将会被保证按顺序发送。
-
NIO基于选择器,在那里可以请求在Channel的状态发生变化时得到通知。选择器运行在一个检查变化并对其做出相应响应的线程上,在应用程序对状态的改变做出响应之后,选择器将会被重置,并将重复这个过程。
-
相比于ByteBuffer只有一个索引用来读和写(使用flip()在读模式和写模式之间进行切换),ByteBuf分别有一个读索引和写索引。
-
ByteBuf的get和set方法不会改变读写索引,read和write方法会改变读写索引。
-
ByteBuf的直接缓冲区和堆缓冲区。
-
PooledByteBufAllocator(池化ByteBuf,最大限度减少内存碎片,使用了jemalloc的高效方法来分配内存)。
-
ByteBuf使用引用计数来释放对象,其实现了ReferenceCounted接口,和jvm不同的是,一般由最后访问(引用计数)对象的那一方来负责将它释放。
-
ChannelHandler处理事件的时候,通过调用ChannelHandlerContext实现,将事件转发给同一个超类型的下一个ChannelHandler。ChannelHandler通过ChannelHandlerContext和ChannelPipeline或者说其他的ChannelHandler交互。
-
每一个ChannelHandler通过EventLoop(I/O线程)来处理传递给它的事件。所以不要阻塞这个线程。
-
ChannelHandlerContext代表了ChannelHandler和ChannelPipeline之间的关联。
-
ChannelHandlerContext有很多的方法,其中一些方法也存在于Channel和ChannelPipeline本身上,但是Channel或者ChannelPipeline上的这些方法会沿着整个ChannelPipeline进行传播,而调用位于ChannelHandlerContext的相同方法,只会传播给位于该ChannelPipeline中的下一个能够处理该事件的ChannelHandler。
25. 如果要将一个ChannelHandler添加到多个ChannelPipeline中去,Channelhandler必须使用@Sharable
注解,否则会报错,同时要保证这个ChannelHandler是线程安全
的。
-
同一个EventLoop会被多个Channel共享,这使得可以通过尽可能少量的Thread来支撑大量的Channel,而不是每个Channel分配一个Thread。
-
因为上图的EventLoop的分配方式可以看到,一个EventLoop可能会被分配给多个Channel,所以对于所有关联的Channel来说,ThreadLocal都将是一样的,所以尽量避免使用。
-
服务器致力于使用一个父Channel来接受来自客户端的连接,并创建子Channel以用于它们之间的通信;而客户端将最可能只需要一个单独的、没有父Channel的Channel来用于所有的网络交互。
29. 尽可能地重用EventLoop,以减少线程创建所带来的开销。
30. 编码器是将消息转换成适合于传输的格式(最有可能的是字节流);而对应的解码器则是将网络字节流转换回应用程序的消息格式。所以,编码器操作出站数据,解码器处理入站数据。
- Netty的架构方式使得只需要简单地将一个ChannelHandler添加到ChannelPipeline中,便可以提供一项新功能,甚至像加密这样重要的功能。