Netty中的Channel、ChannelHandler、ChannelHandlerContext以及ChannelPipeline(常见的调用顺序,消息的传递)


原博文,点击这里

调用顺序

代码:NettyPro中protocoltcp模块:Git HUb地址,点击这里
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
这里的L:表示Local
R:表示为Remote

消息的传递

编解码

对于编解码器使用的是out,进行消息的传递

Handler

对于Handler使用的是:
1.ChannelHandlerContext#fireChannelActive()传递到下一个处理器
2.ctx.writeAndFlush与ctx.channel().writeAndFlush传递到出站处理器。

1.Channel

定义:一个Channel表示一个通道,跟io中的stream的角色一样,但是有几点不同。 1. stream是单向的,只支持读或者写,channel是双向的,既支持读也支持写。2. stream是阻塞的,channel是并行的。

其中Channel的生命周期状态如下:

状态说明说明
channelUnregisteredchannel创建之后,还未注册到EventLoop
channelRegisteredchannel注册到了对应的EventLoop
channelActivechannel处于活跃状态,活跃状态表示已经连接到了远程服务器,现在可以接收和发送数据
channelInactivechannel未连接到远程服务器

一个Channel正常的生命周期如下:

channelRegistered -> channelActice -> channelInactive -> channelUnregistered

在另外一种特殊情况下,会发生多次channelRegistered和channelUnregistered,这是因为用户可以从EventLoop上取消注册Channel来阻止事件的执行并在之后重新注册。状态变化如下:

2.ChannelHandler

ChannelHandler有2种类型:

1.Inbound Handler: 处理inbound数据(接收到的数据)以及所有类型的channel状态修改事件
2.Outbound Handler: 处理outbound数据(发送出去的数据)并且可以拦截各种操作,比如bind、connect、disconnect、close、write等操作
Inbound和Outbound Handler都属于ChannelHandler,它们都可以被添加到ChannelPipeline中,它们内部也提供了handlerAdded、handlerRemoved这两种方法分别在ChannelHandler添加到ChannelPipeline和ChannelHandler从ChannelPipeline中被删除的时候触发。

2.1ChannelInboundHandler

ChannelInboundHandler方法在两种情况下触发:channel状态的改变和channel接收到数据。

一些方法说明:

方法名描述
channelRegistered(…)Channel注册到EventLoop,并且可以处理IO请求
channelUnregistered(…)Channel从EventLoop中被取消注册,并且不能处理任何IO请求
channelActive(…)Channel已经连接到远程服务器,并准备好了接收数据
channelInactive(…)Channel还没有连接到远程服务器
channelReadComplete(…)Channel的读取操作已经完成
channelRead(…)有数据可以读取的时候触发
userEventTriggered(…)当用户调用Channel.fireUserEventTriggered方法的时候触发,用户可以传递一个自定义的对象当这个方法里

ChannelInboundHandler有一个实现ChannelInboundHandlerAdapter,它实现了所有的方法,我们只需要继承这个类然后复写需要的方法即可。

ChannelInboundHandler中的channelRead方法中有读取的ByteBuf。由于Netty在ByteBuf的使用上使用了池的概念,当不需要这个ByteBuf的时候需要进行资源的释放以减少内存的消耗。

@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) {
      // do something
      ReferenceCountUtil.release(msg);
}

Netty内部提供了一个SimpleChannelInboundHandler类,这个类读取数据会自动释放资源。它继承ChannelInboundHandlerAdapter并复写了channelRead方法,在channelRead方法里面finally代码里会自动release资源,并提供了channelRead0方法:

@Override
public void channelRead0(ChannelHandlerContext ctx, Object msg) {
      // do something, do not need release
}

2.2选择和使用

所以一般使用ChannelInboundHandler的话,有3种方法。

直接实现ChannelInBoundHandler接口
继承ChannelInboundHandlerAdapter
继承SimpleChannelInboundHandler
第1种基本不用,第3种用来处理接收消息,第2种用来处理事件状态的改变

3.ChannelOutboundHandler

ChannelOutboundHandler方法在两种情况下触发:发送数据和拦截操作。

ChannelOutboundHandler有一个强大的功能,可以按需推迟一个操作,这使得处理请求可以用到更为复杂的策略。比如,如果写数据到远端被暂停,你可以推迟flush操作,稍后再试。

一些方法说明:

方法名描述
bind(…)请求绑定channel到本地地址
connect(…)channel连接到远程地址
disconnect(…)channel从远程服务器上断开
close(…)关闭channel
deregister(…)取消channel在eventloop上的注册
read(…)在channel中读数据
flush(…)flush数据到远程服务器
write(…)写数据到远程服务器

ChannelOutboundHandler有一个实现ChannelOutboundHandlerAdapter,它实现了所有的方法,我们只需要继承这个类然后复写需要的方法即可。

在outboundhandler中有时候也需要释放资源,当消息被消费并且不再需要传递给下一个outbound handler的时候,调用ReferenceCountUtil.release(message)释放消息。

当消息被写回去或者channel关闭的时候,这个消息的资源会被自动释放,所以没有一个类似SimpleChannelInboundHandler的概念。

ChannelHandlerContext

当ChannelHandler被添加到ChannelPipeline中的时候,ChannelHandlerContext会被创建。
所以说ChannelHandlerContext属于ChannelHandler。

可以通过ChannelHandlerContext的channel方法得到Channel和pipeline方法得到ChannelPipeline。

ChannelHandlerContext可以被保留下来并且在其他地方进行调用,比如在其他线程,或者在handler外部进行调用。

可以使用以下方法保留ChannelHandlerContext:

class WriterHandler extends ChannelHandlerAdapter {
  private ChannelHandlerContext ctx;

  @Override
  public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
      this.ctx = ctx;
  }

  public void send(String msg) {
      ctx.write(msg);
  }
}

Netty中提供了一个@Sharable注解用来将一个实例的ChannelHandler添加到多个ChannelPipeline中,如果不加上这个注解,被多个ChannelPipeline使用的话会抛出异常。

ChannelPipeline

多个ChannelHandler可以组成一个ChannelPipeline,里面的每个ChannelHandler可以转发给下一个ChannelHandler。

ChannelPipeline内部的所有ChannelHandler的处理流程图:

ChannelPipeline提供了多种方法用于添加或删除或代替ChannelHandler,比如addLast, addFirst, remove, replace等方法。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值