测试handler的运行过程
1、测试用例包括两个InboundHandler与OuuboundHandler 2、所有的导包都没有在代码中,需要自行添加
public class NettyServer {
public static void main(String[] args) throws InterruptedException {
// 创建线程池 接受连接
NioEventLoopGroup bossGroup = new NioEventLoopGroup();
// 创建线程池,处理io
NioEventLoopGroup workGroup = new NioEventLoopGroup();
// 创建服务器端启动助手
ServerBootstrap serverBootstrap = new ServerBootstrap();
// 配置启动助手
serverBootstrap.group(bossGroup, workGroup)//设置两个线程池
.channel(NioServerSocketChannel.class)//使用作为服务器端的通道实现
.option(ChannelOption.SO_BACKLOG, 128)//设置线程队列中等待连接的个数
.childOption(ChannelOption.SO_KEEPALIVE, true)//保持活动连接状态
.childHandler(new ChannelInitializer<SocketChannel>() { //创建通道初始化的对象
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast("decoder",new StringDecoder());
pipeline.addLast("encoder",new StringEncoder());
pipeline.addLast(new NettyServerOutHandler());
pipeline.addLast(new NettyServerOutHandler2());
pipeline.addLast(new NettyServerInHandler());
pipeline.addLast(new NettyServerInHandler2());
}
});
System.out.println("----------------server is ready--------------------");
ChannelFuture cf = serverBootstrap.bind(9999).sync();//绑定端口,异步
System.out.println("----------------server is starting--------------------");
// 关闭通道、关闭通道组
cf.channel().closeFuture().sync();
bossGroup.shutdownGracefully();
workGroup.shutdownGracefully();
}
}
public class NettyServerInHandler extends ChannelInboundHandlerAdapter {
@Override
public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
System.out.println("NettyServerInHandler channelRegistered");
}
@Override
public void channelUnregistered(ChannelHandlerContext ctx) throws Exception {
System.out.println("NettyServerInHandler channelUnregistered");
}
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
System.out.println("NettyServerInHandler channelActive");
}
@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
System.out.println("NettyServerInHandler channelInactive");
}
@Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
System.out.println("NettyServerInHandler channelReadComplete");
ctx.channel().writeAndFlush("服务器发送0-0");
}
@Override
public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
System.out.println("NettyServerInHandler userEventTriggered");
}
@Override
public void channelWritabilityChanged(ChannelHandlerContext ctx) throws Exception {
System.out.println("NettyServerInHandler channelWritabilityChanged");
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
System.out.println("NettyServerInHandler exceptionCaught");
}
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
System.out.println("NettyServerInHandler channelRead接收到客户端的数据:"+(String)msg);
// 事件传播
ctx.fireChannelRead(msg);
}
}
public class NettyServerInHandler2 extends ChannelInboundHandlerAdapter {
@Override
public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
System.out.println("NettyServerInHandler2 channelRegistered");
}
@Override
public void channelUnregistered(ChannelHandlerContext ctx) throws Exception {
System.out.println("NettyServerInHandler2 channelUnregistered");
}
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
System.out.println("NettyServerInHandler2 channelActive");
}
@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
System.out.println("NettyServerInHandler2 channelInactive");
}
@Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
System.out.println("NettyServerInHandler2 channelReadComplete");
ctx.channel().writeAndFlush("服务器发送0-0");
}
@Override
public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
System.out.println("NettyServerInHandler2 userEventTriggered");
}
@Override
public void channelWritabilityChanged(ChannelHandlerContext ctx) throws Exception {
System.out.println("NettyServerInHandler2 channelWritabilityChanged");
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
System.out.println("NettyServerInHandler2 exceptionCaught");
}
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
System.out.println("NettyServerInHandler2 channelRead接收到客户端的数据:"+(String)msg);
}
}
public class NettyServerOutHandler extends ChannelOutboundHandlerAdapter {
/**
* 写数据
* @param ctx
* @param msg
* @param promise
* @throws Exception
*/
@Override
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
System.out.println("ServerOutHandler:"+(String) msg);
ctx.write(msg,promise);
}
}
public class NettyServerOutHandler2 extends ChannelOutboundHandlerAdapter {
/**
* 写数据
* @param ctx
* @param msg
* @param promise
* @throws Exception
*/
@Override
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
System.out.println("ServerOutHandler2:"+(String) msg);
ctx.write(msg,promise);
}
}
public class NettyClient {
public static void main(String[] args) throws InterruptedException {
// 创建一个线程组
NioEventLoopGroup group = new NioEventLoopGroup();
//2. 创建客户端的启动助手,完成相关配置
Bootstrap bootstrap = new Bootstrap();
bootstrap.group(group)//3. 设置线程组
.channel(NioSocketChannel.class)//4. 设置客户端通道的实现类
.handler(new ChannelInitializer<SocketChannel>() {//5. 创建一个通道初始化对象
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast("encoder",new StringEncoder());
pipeline.addLast("decoder",new StringDecoder());
pipeline.addLast(new NettyClientHandler());//6.往Pipeline链中添加自定义的handler
}
});
System.out.println("......Client is ready......");
//7.启动客户端去连接服务器端 connect方法是异步的 sync方法是同步阻塞的
ChannelFuture cf = bootstrap.connect("127.0.0.1", 9999).sync();
// 发送消息
cf.channel().writeAndFlush("哈哈哈");
// 关闭连接
cf.channel().closeFuture().sync();
}
}
public class NettyClientHandler extends SimpleChannelInboundHandler<String> {
/**
* 读数据
* @param ctx
* @param msg
* @throws Exception
*/
@Override
protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
System.out.println("服务器发来消息:"+msg);
}
}
服务器端: ----------------server is ready-------------------- ----------------server is starting-------------------- NettyServerInHandler channelRegistered NettyServerInHandler channelActive NettyServerInHandler channelRead接收到客户端的数据:哈哈哈 NettyServerInHandler2 channelRead接收到客户端的数据:哈哈哈 NettyServerInHandler channelReadComplete ServerOutHandler2:服务器发送0-0 ServerOutHandler:服务器发送0-0
客户端: ......Client is ready...... 服务器发来消息:服务器发送0-0
强制关闭客户端: NettyServerInHandler channelReadComplete ServerOutHandler2:服务器发送0-0 ServerOutHandler:服务器发送0-0 NettyServerInHandler exceptionCaught NettyServerInHandler userEventTriggered NettyServerInHandler channelInactive NettyServerInHandler channelUnregistered
由此可以看出,inboundHandler的执行顺序是: channelRegistered→channelActive→channelRead→传播到第二个inboundhandler的channelRead →channelReadComplete→往上一个ServerOutHandler2→再往上ServerOutHandler传播,最后发送到客户端NettyClientInHandler的channelRead中接收到数据。
异常出现的执行顺序: channelReadComplete→exceptionCaught→userEventTriggered→channelInactive→channelUnregistered。
分析得出: 1、通道先注册再会处于活跃状态 2、通道read结束后才会触发readComplete 3、当inboundHandler中触发一个write方法,就会往该链上的上一个outboundHandler中触发write方法,然后再往上触发,直到没有outboundHandler为止,就会发送消息到客户端。 4、通道关闭会再次触发readComplete,然后触发异常方法exceptionCaught,接下来触发userEventTriggered,最后触发channelInactive与channelUnregistered。 5、readComplete方法是在所有的inboundHandler跑完之后才触发的方法,并且只会触发第一个inboundHandler的readComplete方法。