我是靠谱客的博主 快乐小丸子,最近开发中收集的这篇文章主要介绍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<SocketChannel>() {
                        @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();
            // 可以简写为
            /* b.bind(portNumber).sync().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<String> {
    /**
     * 当连接到server成功时,执行的方法
     */
    @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生命周期方法,可以完成对异常事件的监控、断链重连等工作。

最后

以上就是快乐小丸子为你收集整理的Netty源码解析-Channel生命周期与ChannelHandler处理方法的全部内容,希望文章能够帮你解决Netty源码解析-Channel生命周期与ChannelHandler处理方法所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(48)

评论列表共有 0 条评论

立即
投稿
返回
顶部