栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Netty源码解析-Channel生命周期与ChannelHandler处理方法

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Netty源码解析-Channel生命周期与ChannelHandler处理方法

前言:

在之前的文章中,我们已经熟练的使用了ChannelHandler来处理各种请求。同时也了解了各Channel的不同,后续会继续详细介绍SocketChannel和ServerSocketChannel等相关知识点。

在本文中我们来了解下Channel的生命周期(也就是一个客户端连接SocketChannel从连接完成到最后关闭经历过哪些阶段),和其触发的ChannelHandler的那些方法,以期对这两者之间有更好的理解。

1.示例准备

示例的话,我们还是使用之前的示例,在这里主要展示Server端的代码

1.1 HelloServer示例代码
public class HelloServer {
    private static final int PORT = 18080;

    public static void main(String[] args) {

        // 设置boss线程池
        EventLoopGroup bossGroup = new NioEventLoopGroup(1);
        // 设置work线程池
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        try {
            ServerBootstrap b = new ServerBootstrap();
            b.group(bossGroup, workerGroup)
                    // 指定处理channel
                    .channel(NioServerSocketChannel.class)
                    // 设置属性值
                    .option(ChannelOption.SO_BACKLOG, 100)
                    // 指定server处理Handler
                    .handler(new LoggingHandler(LogLevel.INFO))
                    // 指定client处理Handler
                    .childHandler(new ChannelInitializer() {
                        @Override
                        protected void initChannel(SocketChannel ch) throws Exception {
                            ChannelPipeline pipeline = ch.pipeline();
                            pipeline.addLast("frame", new DelimiterbasedframeDecoder(1024, Delimiters.lineDelimiter()));
                            pipeline.addLast("idle", new IdleStateHandler(10, 10, 10));
                            pipeline.addLast("idledeal", new IdleEventHandler());
                            pipeline.addLast("decoder", new StringDecoder());
                            pipeline.addLast("encoder", new StringEncoder());
                            // 主要在这里添加了自定义的Handler
                            pipeline.addLast("handler", new HelloServerHandler());
                        }
                    });
            // 绑定端口监听
            ChannelFuture f = b.bind(PORT).sync();
            // 监听服务器关闭监听
            f.channel().closeFuture().sync();
            // 可以简写为
            
        } catch (Exception ex) {
            ex.printStackTrace();
        } finally {
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }
}
1.2 HelloServerHandler 自定义业务处理
public class HelloServerHandler extends ChannelInboundHandlerAdapter {

    @Override
    public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
        System.out.println("client " + ctx.channel().remoteAddress() + " handlerAdded");
        super.handlerAdded(ctx);
    }

    @Override
    public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
        System.out.println("client " + ctx.channel().remoteAddress() + " channelRegistered");
        super.channelRegistered(ctx);
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        System.out.println("client " + ctx.channel().remoteAddress() + " channelActive");
        super.channelActive(ctx);
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        System.out.println("client " + ctx.channel().remoteAddress() + " read");
        super.channelRead(ctx, msg);
    }

    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        System.out.println("client " + ctx.channel().remoteAddress() + " channelReadComplete");
        super.channelReadComplete(ctx);
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        System.out.println("client " + ctx.channel().remoteAddress() + " channelInactive");
        super.channelActive(ctx);
    }

    @Override
    public void channelUnregistered(ChannelHandlerContext ctx) throws Exception {
        System.out.println("client " + ctx.channel().remoteAddress() + " channelUnregistered");
        super.channelUnregistered(ctx);
    }

    @Override
    public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
        System.out.println("client " + ctx.channel().remoteAddress() + " handlerRemoved");
        super.handlerRemoved(ctx);
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        System.out.println("client " + ctx.channel().remoteAddress() + " exceptionCaught");
        super.exceptionCaught(ctx, cause);
    }
}

处理方式很简单,就是在每种方法处理之前先打印一句日志。

1.3 客户端

客户端在连接完成后,直接向服务端发送一句请求

public class HelloClientHandler extends SimpleChannelInboundHandler {
    
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        System.out.println("client active");
        ctx.writeAndFlush("hello servern");
        super.channelActive(ctx);
    }
}

根据当前示例,客户端在连接到服务端时,会主动发送hello server;服务端使用IdleStateHandler来检测客户端空闲,当检测到客户端一段时间内没有请求,则直接close当前channel。

我们来看下最终client和server都启动后,server端的日志

client /127.0.0.1:33707 handlerAdded
client /127.0.0.1:33707 channelRegistered
client /127.0.0.1:33707 channelActive
client /127.0.0.1:33707 read
client /127.0.0.1:33707 channelReadComplete
idle...
client /127.0.0.1:33707 channelInactive
client /127.0.0.1:33707 channelUnregistered
client /127.0.0.1:33707 handlerRemoved

这个日志展示了一个完整的客户端channel从连接、发送请求、关闭连接的全过程,下面我们依据此来分析下Channel的生命周期和对应的ChannelHandler处理

2.Channel生命周期
状态描述
channelRegisteredchannel已经注册到EventLoop上,此时EventLoop可以监听Channel的read/write等事件
channelActivechannel处于活跃状态,此时可以接收、发送数据
channelInactivechannel没有连接到server
channelUnregisteredchannel已经创建,但是还没有注册到EventLoop上

当Channel的状态发生变化时,便会生成对应的事件,这些事件将会被转发给ChannelPipeline,随后ChannelPipeline会对这些事件作出响应(本质上是调用ChannelHandler的对应方法来完成)

下面我们通过ChannelHandler的生命周期方法来综合起来学习下。

3.ChannelHandler的生命周期

本质上ChannelHandler并没有生命周期的概念,因为ChannelHandler的方法调用都是被动的,都是Channel的生命周期状态发生变化被动调用造成的。

但是为了便于分析,我们便使用生命周期这个概念来说明。

3.1 Channel新连接建立相关事件

handlerAdded -> channelRegistered -> channelActive

当新的客户端连接到服务端之后,会依次调用上面三个ChannelHandler的方法,完成ChannelPipeline对ChannelHandler的添加;当前channel注册到EventLoop;激活当前channel;

3.2 EventLoop监听Channel read事件

channelRead -> channelReadComplete

当客户端发送请求信息到服务端时,会调用channelRead()方法完成请求信息读取;读取完成后则调用channelReadComplete()方法,表示此次读事件完成;

3.3 channel关闭

channelInactive -> channelUnregistered -> handlerRemoved

客户端完成请求后,会关闭连接(或者长时间没有请求被服务端主动close掉),关闭连接时,服务端检测到该channel的关闭,则依次调用上述三个方法来完成channel的注销删除。

3.4 channel读取信息异常

exceptionCaught

当channel在读取数据时发生异常,则抛出,此时会调用ChannelPipeline.fireExceptionCaught()方法,后续依次调用ChannelHandler.exceptionCaught()方法来完成异常处理

总结:

依据以上的分析,我们知道了在Channel的不同生命周期,会调用ChannelHandler的不同方法来完成生命周期的转换。

后续通过重写ChannelHandler生命周期方法,可以完成对异常事件的监控、断链重连等工作。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/683375.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号