一 channel
1、 Channel作用,核心模块知识点,生命周期等(封装了Java Nio)
什么是Channel: 客户端和服务端建立的一个连接通道
什么是ChannelHandler: 负责Channel的逻辑处理
什么是ChannelPipeline: 负责管理ChannelHandler的有序容器
他们是什么关系:
一个Channel包含一个ChannelPipeline,所有ChannelHandler都会顺序加入到ChannelPipeline中
创建Channel时会自动创建一个ChannelPipeline,每个Channel都有一个管理它的pipeline,这关联是永久性的
Channel当状态出现变化,就会触发对应的事件
状态:
(1)channelRegistered: channel注册到一个EventLoop
(2)channelUnregistered: channel已经创建,但是未注册到一个EventLoop里面,也就是没有和Selector绑定
(3)channelInactive: channel处于非活跃状态,没有连接到远程主机
(4)channelActive: 变为活跃状态(连接到了远程主机),可以接受和发送数据
channelHandler的事件与channel的事件是关联的(近乎相似)
二 channel Handler ChannelPipeline
1、 channelHandler:
handlerAdded : 当 ChannelHandler(逻辑处理) 添加到 ChannelPipeline 调用
handlerRemoved : 当 ChannelHandler 从 ChannelPipeline 移除时调用
exceptionCaught : 执行抛出异常时调用
Sharable: 共享handler用的
(1)ChannelHandler下主要是两个子接口
1)hannelInboundHandler
2)ChannelOutboundHandler
ChannelInboundHandler:(入站)
处理输入数据和Channel状态类型改变,
适配器 ChannelInboundHandlerAdapter(适配器设计模式)
常用的:SimpleChannelInboundHandler
ChannelOutboundHandler:(出站)
处理输出数据,适配器 ChannelOutboundHandlerAdapter
生命周期的查看:
里面有其他的方法也读数据了所以出现多个readComplete
可以根据生命周期实现上下线人数
2、 ChannelPipeline: 对handler进行管理
好比厂里的流水线一样,可以在上面添加多个ChannelHanler,也可看成是一串 ChannelHandler 实例,拦截穿过 Channel 的输入输出 event, ChannelPipeline 实现了拦截器的一种高级形式,使得用户可以对事件的处理以及ChannelHanler之间交互获得完全的控制权
三 、Netty核心模块ChannelHandlerContext模块
作用和分析
1、连接ChannelHandler和ChannelPipeline的桥梁
ChannelHandlerContext部分方法和Channel及ChannelPipeline重合,好比调用write方法,
Channel、ChannelPipeline、(触发一个事件 在整个管道里流通 )
ChannelHandlerContext (后续的handler 会跳过之前的handler 插队)
都可以调用此方法,前两者都会在整个管道流里传播,而ChannelHandlerContext就只会在后续的Handler里面传播
2、AbstractChannelHandlerContext类
双向链表结构,next/prev分别是后继节点,和前驱节点
3、DefaultChannelHandlerContext 是实现类,但是大部分都是父类那边完成,这个只是简单的实现一些方法
主要就是判断Handler的类型
上面继承的handler
4、ChannelInboundHandler之间的传递,主要通过调用ctx里面的FireXXX()方法来实现下个handler的调用
四、 Netty案例实战常见问题之入站出站Handler执行顺序
讲解多个入站出站ChannelHandler的执行顺序
1、一般的项目中,inboundHandler和outboundHandler有多个,在Pipeline中的执行顺序?
InboundHandler顺序执行,OutboundHandler逆序执行
i1 i2 o1 o2
这样o1 o2没有执行
修改后
问题:
ch.pipeline().addLast(new InboundHandler1());
ch.pipeline().addLast(new OutboundHandler1());
ch.pipeline().addLast(new OutboundHandler2());
ch.pipeline().addLast(new InboundHandler2());
或者:
ch.pipeline().addLast(new OutboundHandler1());
ch.pipeline().addLast(new OutboundHandler2());
ch.pipeline().addLast(new InboundHandler1());
ch.pipeline().addLast(new InboundHandler2());
执行顺序是:
InboundHandler1 channelRead
InboundHandler2 channelRead
OutboundHandler2 write
OutboundHandler1 write
结论:
1)InboundHandler顺序执行,OutboundHandler逆序执行
2)InboundHandler之间传递数据,通过ctx.fireChannelRead(msg)
3)InboundHandler通过ctx.write(msg),则会传递到outboundHandler
4) 使用ctx.write(msg)传递消息,Inbound需要放在结尾,在Outbound之后,不然outboundhandler会不执行;
但是使用channel.write(msg)、pipline.write(msg)情况会不一致,都会执行
5) outBound和Inbound谁先执行,针对客户端和服务端而言,客户端是发起请求再接受数据,先outbound再inbound,服务端则相反
五、异步操作模块ChannelFuture(worker线程)
回顾:
等待5s后才返回
简介:ChannelFuture异步操作模块及使用注意事项
Netty中的所有I/O操作都是异步的,这意味任何I/O调用都会立即返回,而ChannelFuture会提供有关的信息I/O操作的结果或状态。
1、ChannelFuture状态:
1) 未完成:当I/O操作开始时,将创建一个新的future对象,新的最初是未完成的 - 它既没有成功,也没有失败,也没有被取消,因为I/O操作尚未完成。
2)已完成:当I/O操作完成,不管是成功、失败还是取消,Future都是标记为已完成的, 失败的时候也有具体的信息,例如原因失败,但请注意,即使失败和取消属于完成状态。
注意:不要在IO线程内调用future对象的sync或者await方法
不能在channelHandler中调用sync或者await方法(有否则的方法创建一个线程池)
2、 方法
3、 ChannelPromise:继承ChannelFuture,进一步拓展用于设置IO操作的结果
五、ByteBuf
Netty核心之ByteBuf介绍,对比JDK原生ByteBuffer
ByteBuf:是数据容器(字节容器)
JDK ByteBuffer
共用读写索引,每次读写操作都需要复位Flip()
扩容麻烦,而且扩容后容易造成浪费(可以进行估算但是很不灵活)
Netty ByteBuf
读写使用不同的索引,所以操作便捷
自动扩容,使用便捷
读索引=写索引的时候进行越界的错误
抽象类所以要通过工具进行对象的闯创建
不够的时候会自动扩充容量