Channel的生命周期状态【状态转换将变为相应的事件,转发给ChannelPipeline中的ChannelHandler进行处理】
ChannelUnregistered:Channel已经被创建,但还未注册到EventLoop
ChannelRegistered:Channel已经被注册到了EventLoop
ChannelActive:Channel处于活动状态(已经连接到它的远程节点)。它现在可以接收和发送数据了
ChannelInactive:Channel没有连接到远程节点
ChannelHandler的生命周期【加入或者移除ChannelPipeline时调用这些方法,其有2个子类ChannelInboundHandler ChannelOutboundHandler】
handlerAdded:当把ChannelHandler添加到ChannelPipeline中时被调用
handlerRemoved:当从ChannelPipeline中移除ChannelHandler时被调用
exceptionCaught:当处理过程中在ChannelPipeline中有错误产生时被调用
ChannelInboundHandler接口【入站】
channelRegistered:当Channel已经注册到它的EventLoop并且能够处理I/O时被调用
channelUnregistered:当Channel从它的EventLoop注销并且无法处理任何I/O时被调用
channelActive:当Channel处于活动状态时被调用;Channel已经连接/绑定并且已经就绪
channelInactive:当Channel离开活动状态并且不再连接它的远程节点时被调用
channelReadComplete:当Channel上的一个读操作完成时被调用
channelRead:当从Channel读取数据时被调用 【channelRead0是通过SimpleChannelInboundHandler的方法】
ChannelWritability Changed:当Channel的可写状态发生改变时被调用。用户可以确保写操作不会完成得太快(以避免发生OutOfMemoryError)或者可以在Channel变为再次可写时恢复写入。可以通过调用Channel的isWritable()方法来检测Channel的可写性。与可写性相关的阈值可以通过Channel.config(). setWriteHighWaterMark()和 Channel.config().setWriteLowWater- Mark()方法来设置
userEventTriggered:当ChannelnboundHandler.fireUserEventTriggered()方法被调用时被调用,因为一个POJO被传经了ChannelPipeline
ChannelOutboundHandler接口【出站 按需推迟操作或者事件(下载文件被暂停)】 channel->ChannelPipeline->ChannelOutboundHandler
bind(ChannelHandlerContext,SocketAddress,ChannelPromise):当请求将Channel绑定到本地地址时被调用
connect(ChannelHandlerContext,SocketAddress,SocketAddress,ChannelPromise):当请求将Channel连接到远程节点时被调用
disconnect(ChannelHandlerContext,ChannelPromise):当请求将Channel从远程节点断开时被调用
close(ChannelHandlerContext,ChannelPromise):当请求关闭Channel时被调用
deregister(ChannelHandlerContext,ChannelPromise):当请求将Channel从它的EventLoop注销时被调用
read(ChannelHandlerContext):当请求从Channel读取更多的数据时被调用
flush(ChannelHandlerContext):当请求通过Channel将入队数据冲刷到远程节点时被调用
write(ChannelHandlerContext,Object,ChannelPromise):当请求通过Channel将数据写到远程节点时被调用
资源泄漏:Netty提供了class ResourceLeakDetector 【java -Dio.netty.leakDetectionLevel=ADVANCED】
ChannelPipeline接口【每一个新创建的Channel都将会被分配一个新的ChannelPipeline】
ChannelPipeline保存了与Channel相关联的ChannelHandler;
ChannelPipeline可以根据需要,通过添加或者删除ChannelHandler来动态地修改;
ChannelPipeline有着丰富的API用以被调用,以响应入站和出站事件
ChannelHanlderContext【每加入一个Handler,就会绑定一个新建的ChannelHanlderContext】
可以通过调用ChannelHandlerContext上的pipeline()方法来获得被封闭的ChannelPipeline的引用。这使得运行时得以操作ChannelPipeline的ChannelHandler,我们可以利用这一点来实现一些复杂的设计。例如,你可以通过将ChannelHandler添加到ChannelPipeline中来实现动态的协议切换。
异常处理
ChannelHandler.exceptionCaught()的默认实现是简单地将当前异常转发给ChannelPipeline中的下一个ChannelHandler;
如果异常到达了ChannelPipeline的尾端,它将会被记录为未被处理;
要想定义自定义的处理逻辑,你需要重写exceptionCaught()方法。然后你需要决定是否需要将该异常传播出去。
每个EventLoop都由一个Thread支撑 EventLoopGroup bossGroup = new NioEventLoopGroup();//默认创建的Thread数值为Math.max(1, SystemPropertyUtil.getInt("io.netty.eventLoopThreads", NettyRuntime.availableProcessors() * 2));
EventLoopGroup oiobossGroup = new OioEventLoopGroup();
AbstractBootstrap<B extends AbstractBootstrap<B, C>, C extends Channel>
B extends AbstractBootstarp<B,C> 子类型是父类型的一个参数类型,可以在运行时返回实例的引用以支持链式方式的调用Bootstrap 与 ServerBootstrap方法
Bootstrap group(EventLoopGroup):设置用于处理Channel所有事件的EventLoopGroup
Bootstrap channel(Class<? extends C>)Bootstrap channelFactory(ChannelFactory<? extends C>):channel()方法指定了Channel的实现类。如果该实现类没提供默认的构造函数[7],可以通过调用channel- Factory()方法来指定一个工厂类,它将会被bind()方法调用
<T> Bootstrap option(ChannelOption<T> option,T value):设置ChannelOption,其将被应用到每个新创建的Channel的ChannelConfig。这些选项将会通过bind()或者connect()方法设置到Channel,不管哪个先被调用。这个方法在Channel已经被创建后再调用将不会有任何的效果。支持的ChannelOption取决于使用的Channel类型。
<T> Bootstrap attr(Attribute<T> key, T value):指定新创建的Channel的属性值。这些属性值是通过bind()或者connect()方法设置到Channel的,具体取决于谁最先被调用。这个方法在Channel被创建后将不会有任何的效果。
Bootstrap handler(ChannelHandler):设置将被添加到ChannelPipeline以接收事件通知的ChannelHandler
Bootstrap clone():创建一个当前Bootstrap的克隆,其具有和原始的Bootstrap相同的设置信息
Bootstrap remoteAddress(SocketAddress):设置远程地址。或者,也可以通过connect()方法来指定它
ChannelFuture connect():连接到远程节点并返回一个ChannelFuture,其将会在连接操作完成后接收到通知
ChannelFuture bind():绑定Channel并返回一个ChannelFuture,其将会在绑定操作完成后接收到通知,在那之后必须调用Channel. connect()方法来建立连接
EventLoopGroup bossGroup = new NioEventLoopGroup();//处理channel所有事件的group ServerBootstrap serverBootstrap = new ServerBootstrap();//创建和连接新的服务端channel serverBootstrap.group(bossGroup, workerGroup)//提供处理新链接channel事件的事件组 .channel(NioServerSocketChannel.class)//指定所用的channel .childHandler(new ChannelInitializer<SocketChannel>() {//设置处理channel事件和数据的handler @Override public void initChannel(SocketChannel ch) throws Exception {
ServerBootstrap bootstrap = new ServerBootstrap(); // ← -- 创建ServerBootstrap 以创建ServerSocketChannel,并绑定它 bootstrap.group(new NioEventLoopGroup(), new NioEventLoopGroup())// ← -- 设置EventLoopGroup,其将提供用以处理Channel 事件的EventLoop .channel(NioServerSocketChannel.class)// ← -- 指定要使用的Channel 实现 .childHandler(// ← -- 设置用于处理已被接受的子Channel 的I/O 和数据的ChannelInboundHandler new SimpleChannelInboundHandler<ByteBuf>() { ChannelFuture connectFuture; @Override public void channelActive(ChannelHandlerContext ctx) throws Exception { Bootstrap bootstrap = new Bootstrap();// ← -- 创建一个Bootstrap类的实例以连接到远程主机 bootstrap.channel(NioSocketChannel.class).handler(// ← -- 指定Channel的实现 new SimpleChannelInboundHandler<ByteBuf>() { // ← -- 为入站I/O 设置ChannelInboundHandler @Override protected void channelRead0( ChannelHandlerContext ctx, ByteBuf in) throws Exception { System.out.println("Received data"); } }); bootstrap.group(ctx.channel().eventLoop());// ← -- 使用与分配给已被接受的子Channel 相同的EventLoop connectFuture = bootstrap.connect( new InetSocketAddress("www.123.com", 80)); // ← -- 连接到远程节点 } @Override protected void channelRead0( ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf) throws Exception { if (connectFuture.isDone()) {//当连接完成时,执行一些数据操作(如代理) } } }); ChannelFuture future = bootstrap.bind(new InetSocketAddress(8080));// ← -- 通过配置好的ServerBootstrap绑定该Server-SocketChannel future.addListener(new ChannelFutureListener() { @Override public void operationComplete(ChannelFuture channelFuture) throws Exception { if (channelFuture.isSuccess()) { System.out.println("Server bound"); } else { System.err.println("Bind attempt failed"); channelFuture.cause().printStackTrace(); } } });
原文:https://www.cnblogs.com/htkj/p/10932637.html