概述
前言:
在之前的文章中,我们已经熟练的使用了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生命周期
状态 | 描述 |
channelRegistered | channel已经注册到EventLoop上,此时EventLoop可以监听Channel的read/write等事件 |
channelActive | channel处于活跃状态,此时可以接收、发送数据 |
channelInactive | channel没有连接到server |
channelUnregistered | channel已经创建,但是还没有注册到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处理方法所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复