原创文章: Future-Listener – 编程屋
-
当Future刚刚创建时,处于非完成状态,调用者可以通过返回的ChannelFuture来获取操作执行的状态,注册监听函数来执行完成后的操作。
-
常见如下操作
-
通过isDone方法判断操作是否完成
-
通过isSuccess方法判断当前已完成的操作是否成功
-
通过getCause方法获取已完成的当前操作失败的原因
-
通过isCancelled判断当前已完成的操作是否被取消
-
通过addListener方法来注册监听器,当操作已完成(isDone方法返回完成),将会通知指定的监听器;如果Future对象已完成,则通知指定的监听器
测试:
服务器代码
package com.liubujun.netty;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
/**
* @Author: liubujun
* @Date: 2023/2/6 17:05
*/
public class NettyServer {
public static void main(String[] args) throws Exception {
//1.创建2个线程组bossGroup和workerGroup
//2 bossGroup只是处理连接请求,workerGroup真正的和客户端进行业务处理
//3 两个都是无限循环
NioEventLoopGroup bossGroup = new NioEventLoopGroup();
NioEventLoopGroup workerGroup = new NioEventLoopGroup();
try {
//创建服务器端的启动对象,配置参数
ServerBootstrap bootstrap = new ServerBootstrap();
bootstrap.group(bossGroup,workerGroup)//设置两个线程组
.channel(NioServerSocketChannel.class) //使用nioSocketChannel作为服务器的通道实现
.option(ChannelOption.SO_BACKLOG,128)//设置线程队列得到连接
.childOption(ChannelOption.SO_KEEPALIVE,true)//设置保持活动连接状态
.childHandler(new ChannelInitializer<SocketChannel>() {
//给pipeline设置处理器
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast(new NettyServerHandler());
}
});//给workerGroup的EventLoop对应的管道设置处理器
System.out.println("....服务器 is ready...");
//绑定一个端口并且同步,生成了一个ChannelFuture对象
//启动服务器(并绑定端口)
ChannelFuture cf = bootstrap.bind(6668).sync();
cf.addListener(new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture channelFuture) throws Exception {
if (cf.isSuccess()){
System.out.println("监听端口6668成功");
}else {
System.out.println("监听端口6668失败");
}
}
});
//对关联通道进行监听
cf.channel().closeFuture().sync();
}finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
}
服务端处理器代码:
package com.liubujun.netty;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.util.CharsetUtil;
import java.time.LocalDateTime;
/**
* @Author: liubujun
* @Date: 2023/2/8 13:25
*/
/**
* 说明:
* 1 说明自定义一个handle 需要继承netty 规定好的某个HandlerAdapter
* 2 这时继承一个Handleer,才能称之为一个Handler
*/
public class NettyServerHandler extends ChannelInboundHandlerAdapter {
//读取数据的事件(这里读取客户端发送的消息)
/**
*
* @param ctx ChannelHandlerContext ctx:上下文对象,含有管道pipeline,通道channel,地址
* @param msg 就是客户端发送的消息
* @throws Exception
*/
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
System.out.println(" server ctx = "+ctx);
ByteBuf buf = (ByteBuf)msg;
System.out.println("客户端发送的消息:"+buf.toString(CharsetUtil.UTF_8));
System.out.println("客户端地址:"+ctx.channel().remoteAddress());
ctx.channel().eventLoop().execute(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 值得注意的是:write 操作只是将消息存入到消息发送环形数组中,并没有真正被发送,只有调用flush 操作才会被写入到Channel 中,发送给对方。
ctx.writeAndFlush(Unpooled.copiedBuffer(LocalDateTime.now()+":第一条异步消息",CharsetUtil.UTF_8));
}
});
ctx.channel().eventLoop().execute(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
ctx.writeAndFlush(Unpooled.copiedBuffer(LocalDateTime.now()+":第二条异步消息",CharsetUtil.UTF_8));
}
});
super.channelRead(ctx, msg);
}
@Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
ctx.writeAndFlush(Unpooled.copiedBuffer(LocalDateTime.now()+" :hello,客户端~",CharsetUtil.UTF_8));
}
//处理异常,一般需要关闭通道
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
ctx.close();
}
}
启动服务端:
以上只是部分内容,为了方便维护,文章已迁移到新地址:Future-Listener – 编程屋