netty学习笔记

相关接口/类

// base
ChannelHandler channelHandler;
ChannelHandlerAdapter channelHandlerAdapter;

// inbound和outbound 的接口和adapter
ChannelInboundHandler channelInboundHandler;
ChannelInboundHandlerAdapter channelInboundHandlerAdapter;
SimpleChannelInboundHandler simpleChannelInboundHandler;
ChannelOutboundHandler channelOutboundHandler;
ChannelOutboundHandlerAdapter channelOutboundHandlerAdapter;

// 单项的Message Decoder和Encoder
ByteToMessageDecoder byteToMessageDecoder;
ReplayingDecoder replayingDecoder;
MessageToMessageDecoder messageToMessageDecoder;
MessageToByteEncoder messageToByteEncoder;

// 双向的Codec
ByteToMessageCodec byteToMessageCodec;
MessageToMessageCodec messageToMessageCodec;

阻塞的业务操作

摘录

也许最常见的是应用程序处理接收到消息后进行解码,然后供相关业务逻辑模块使用。所以应用程序只需要 扩展 SimpleChannelInboundHandler,也就是我们自定义一个继承 SimpleChannelInboundHandler的 handler 类,其中是 handler 可以处理的消息类型。通过重写父类的方法可以获得一个 ChannelHandlerContext 的引用,它们接受一个 ChannelHandlerContext 的参数,你可以在 class 中当一个属性存储。
处理程序关注的主要方法是“channelRead0(ChannelHandlerContext ctx, I msg)”,每当 Netty 调用这个方法, 对象“I”是消息,这里使用了 Java 的泛型设计,程序就能处理 I。如何处理消息完全取决于程序的需要。在处理消息 时有一点需要注意的,在 Netty 中事件处理 IO 一般有很多线程,程序中尽量不要阻塞 IO 线程,因为阻塞会降低程 序的性能。
必须不阻塞 IO 线程意味着在 ChannelHandler 中使用阻塞操作会有问题。幸运的是 Netty 供了解决方案, 我们可以在添加 ChannelHandler 到 ChannelPipeline 中时指定一个EventExecutorGroup,EventExecutorGroup 会获得一个 EventExecutor,EventExecutor 将执行 ChannelHandler 的所有方法。EventExecutor 将使用不同的线 程来执行和释放 EventLoop。

理解

注意,ChannelPipeline ChannelPipeline.addLast(EventExecutorGroup group, ChannelHandler… handlers);这个方法的第一个参数,只对参数里面的ChannelHandler有效,ChannelHandler里的所有方法都在group里执行。

比如:ChannelPipeline添加了三个ChannelHandler,一个编解码和一个log的Handler都是没有group参数的,一个业务ChannelHandler是自己new了一个group。那么在执行的时候,业务ChannelHandler在新的线程group里执行,所以可以执行阻塞操作,不会影响io线程,其余的两个ChannelHandler在io线程里执行。
这样也不会有线程同步问题,因为以前一个ChannelPipeline是在一个线程里按顺序执行。现在一个ChannelPipeline是在两个线程池里的两个线程执行,他们在ChannelPipeline里还是有顺序的,所以不会有线程同步问题。

关于ReferenceCounted 回收

一个ReferenceCounted相关的点

FixedLengthFrameDecoder是按固定长度把ByteBuf拆成多个ByteBuf的InboundHandler。
FixedLengthFrameDecoder.decode方法,return in.readSlice(frameLength).retain();代码,这样返回的ByteBuf的引用就有两次了,为什么要这样?
因为在netty的设计里,在InboundHandler的read方法里,都要把传递进来的msg给release一次,这样这个ByteBuf就会被read几次,就会被release多次。
补充:
* ByteBuf的slice相关方法生成的新的ByteBuf和之前的ByteBuf是共享refCnt(引用次数)的。
* 在Pipeline中,ByteBuf在前一个Handler里生成,传递到下一个Handler里去处理,并且release。

LengthFieldBasedFrameDecoder

理解LengthFieldBasedFrameDecoder的四个参数,看类的doc就能很好的理解。
lengthAdjustment:算body length的时候,用字节里取到的值和这个相加。
initialBytesToStrip:用旧的ByteBuf生成新的ByteBuf时,旧的ByteBuf需要跳过initialBytesToStrip个字节。长度为字节里的长度和lengthAdjustment值的和。

关于异常

对于Inbound,exceptionCaught方法,在read处理方法里抛出异常,会在当前handler的exceptionCaught里捕获,也可以被传递到下一个handler的exceptionCaught方法。

对于Outbound,write方法抛出异常,会在调用它的handler里捕获,并且调用ChannelPromise的tryFailure方法,是对应的Listener回调。

关于socket的关闭

调用Channel或Pipeline或Context的close方法,即能断掉该Channel,把它从EventLoop里清除。

你可能感兴趣的:(♚java♚)