Netty学习笔记_10(Netty核心模块组件)
1、BootStrap,ServerBootStrap
- 一个Netty应用通常由一个BootStrap开始,主要作用是配置整个Netty程序,串联各个组件,Netty中的BootStrap类是客户端程序的启动引导类,ServerBootStrap是服务端启动引导类
- 常见方法:
public ServerBootstrap group (EventLoopGroup parentGroup,
EventLoopGroup childGroup)
作用于服务器端,用来设置两个EventLoop
public B group(EventLoopGroup group)
作用于客户端,用来设置一个EventLoopGroup
public B channel(Class<? extends C> channelClass)
用来设置一个服务端的通道实现
public <T> B option(ChannelOption<T> option, T value)
用来给ServerChannel添加配置
Public <T> ServerBootStrap childOption (ChannelOption<T> childOption, T value)
用来给接收到的通道添加配置
public ServerBootstrap childHandler (ChannelHandler childHandler)
用来设置业务处理类(自定义handler)
childHandler主要针对于服务器端为客户端划分;
public B handler(ChannelHandler handler)
Handler则在服务器端本身发挥作用
public ChannelFuture bind(int inetPort)
用于服务器,设置占用的端口号
public ChannelFuture connect (String inetHost,int inetPort)
该方法用于客户端,用来连接服务器
2、Future,ChannelFuture
- Netty中所有操作都是异步的,不能立即得知消息是否被正确处理,但可以过一会等它执行完成或直接注册一个监听器,具体实现通过Future和ChannelFuture,它们可以注册一个监听,当操作执行成功或失败时,监听会自动触发注册的监听事件
- 常用方法:
Channel channel()
返回当前正在进行IO操作的通道
ChannelFuture sync()
等待异步操作执行完毕
3、Channel
- Channel是Netty网络通信组件,能够用于执行网络IO操作
- 通过Channel可获得当前网络连接的通道状态
- 通过Channel可获得网络连接配置参数
- Channel提供异步的网络IO操作(建立连接,读写,绑定端口),异步调用意味着任何IO调用都将立即返回,但不保证在调用结束时所请求的IO操作已完成
- 调用立即返回一个ChannelFuture实例,通过注册监听器,可以在IO操作成功、失败或取消时回调通知调用方
- 支持关联IO操作与对应的处理程序
- 不同协议、不同的阻塞类型的连接是不同的,Channel类型与之对应,常用的Channel类型有:
NioSocketChannel
异步的客户端TCP socket连接
NioServerSocketChannel
异步的服务器TCP socket连接
NioDatagramChannel
异步的UDP连接
NioSctpChannel
异步的客户端Sctp连接
NioSctpServerChannel
异步的服务端Sctp连接
4、Selector
- Netty基于Selector对象实现IO多路复用,通过Selector一个线程可以监听多个连接的Channel事件
- 当向一个Selector中注册Channel后,Selector内部的机制就可以自动不断地查询(select)这些Channel中是否有就绪的IO事件(可读、可写、完成网络连接等),这样程序就可以简单地使用一个线程高效地管理多个Channel
5、ChannelHandler及其实现类
- ChannelHandler是一个接口,处理IO事件 / 拦截IO操作,并将其转发到其ChannelPipeline(业务处理链)中的下一个处理程序
- ChannelHandler本身并没有提供很多方法,因为这个接口有许多方法需要实现,方便使用的时候,可以继承它的子类
- ChannelHandler及其实现类:
接 口
ChannelInboundHandler 用于处理Channel(通道)入站IO事件; ChannelOutboundHandler 用于处理Channel(通道)出站IO事件; 适 配 器 ChannelOutboundHandlerAdapter 用于处理出站IO操作; ChanneInboundHandlerAdapter 用于处理入站IO操作; ChannelDuplexHandler 用于处理入站和出站事件。
【注】以客户端应用程序为例:如果事件运动方向是客户端服务器,我们称之为“出站”,即客户端发送的数据会通过pipeline中的一系列ChannelOutboundHandler,并被这些Handler处理,反之称为“入站”。
4、自定义handler类继承ChannelInboundHandlerAdapter,通过重写相应方法实现业务逻辑:
public class ChannelInboundHandlerAdapter extends ChannelHandlerAdapter implements ChannelInboundHandler {
public void channelRegistered(ChannelHandlerContext ctx) throws Exception { ctx.fireChannelRegistered(); } public void channelUnregistered(ChannelHandlerContext ctx) throws Exception { ctx.fireChannelUnregistered(); } //通道就绪事件 public void channelActive(ChannelHandlerContext ctx) throws Exception { ctx.fireChannelActive(); } public void channelInactive(ChannelHandlerContext ctx) throws Exception { ctx.fireChannelInactive(); } //通道读取数据事件 public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { ctx.fireChannelRead(msg); } //读取数据完毕 public void channelReadComplete(ChannelHandlerContext ctx) throws Exception { ctx.fireChannelReadComplete(); } public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception { ctx.fireUserEventTriggered(evt); } public void channelWritabilityChanged(ChannelHandlerContext ctx) throws Exception { ctx.fireChannelWritabilityChanged(); } //异常捕获事件 public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { ctx.fireExceptionCaught(cause); } } |
6、Pipeline和ChannelPipeline
- ChannelPipeline是一个handler的集合,负责处理和拦截inbound / outbound的事件或操作。ChannelPipeline是ChannelHandler实例对象的链表
- ChannelPipeline实现了一种高级形式的拦截过滤器模式,用户可以完全控制事件的处理方式,以及Channel中各个ChannelHandler的交互模式
- 一个Channel包含了一个ChannelPipeline,而一个ChannelPipeline中又维护了一个由ChannelHandlerContext组成的双向链表,且每个ChannelHandlerContext中由关联了一个ChannelHandler;
- 入站事件和出站事件在一个双向链表中,入站事件会从链表head往后传递到最后一个入站的handler,出站事件会从链表tail往前传递到第一个出站的handler,两者互不干扰。
...
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast("MyHttpServerCC",new HttpServerCodec());
//增加一个自定义的处理器
pipeline.addLast("MyHttpServerHandler",new TestHttpServerHandler());
断点 System.out.println("ok");
}...
这段代码中显然有两个handler对象HttpServerCodec()和TestHttpServerHandler(),通过debug来观察ChannelPipeline构成的双向链表:
显然,pipeline 对象中包含了一个head和tail,从head中进入,可以看到链表第一个元素为我们编写的初始化文件TestServerInitializer,它本质上也是一个自定义的handler;
而next(下一个)即为HttpServerCodec;
继续next,发现下一个handler为TestHttpServerHandler;
继续next,得到链表尾元素,即默认的DefultChannelPipeline$TailContext,其中不再包含handler;
反向从tail进入,可以发现末尾元素没有handler,且next属性为null,prev指向它的前一个handler,即TestHttpServerHandler;
TestHttpServerHandler的prev指向前一个handler,即HttpServerCodec;
HttpServerCodec的前一个handler则是链表中第一个元素,即TestServerInitializer。
【注】在TestHttpServerHandler中传入的ctx,本质上是DefaultChannelHandlerContext类型的数据
-
常用方法:
ChannelPipeline addFirst(String name, ChannelHandler handler);
把一个业务处理类(handler)添加到链表中第一个位置
ChannelPipeline addLast(EventExecutorGroup group, String name, ChannelHandler handler);
把一个业务处理类(handler)添加到链表中最后一个位置