3.2、Channel
- close() 关闭channel
- closeFuture() 用来处理channel的关闭
- sync() 同步等待channel关闭
- addListener() 异步等待channel关闭
- pipeline() 添加处理器
- write() 将数据写入缓冲区,但不会立即输出
- wrireAndFlush() 写入并刷出
channelfuture详解
public class HelloClient {
public static void main(String[] args) throws InterruptedException {
//1. 启动类
ChannelFuture channelFuture = new Bootstrap()
//2. 添加EventLoop
.group(new NioEventLoopGroup())
//3. 选择客户端channel实现
.channel(NioSocketChannel.class)
//4. 添加处理器
.handler(new ChannelInitializer<NioSocketChannel>() {
@Override
//在连接建立后被调用
protected void initChannel(NioSocketChannel channel) throws Exception {
//编码器,将要发送的消息转为ByteBuf
channel.pipeline().addLast(new StringEncoder());
}
})
//5. 连接到服务器
.connect(new InetSocketAddress(8080));
//阻塞方法,知道连接建立
channelFuture.sync();
//代表连接对象
Channel channel = channelFuture.channel();
//6. 向服务端发送数据
channel.writeAndFlush("hello server");
}
}
- 处理方式1:sync方法同步阻塞等待建立连接 需
//处理方式1:sync同步阻塞,等待建立连接
Channel channel = channelFuture
//阻塞方法,直到连接建立
.sync()
//代表连接对象
.channel();
channel.writeAndFlush("sync-msg...");
System.out.println(channel);
System.out.println("=====");
sync()方法作用。
如果没有sync,因为connect方法是异步非阻塞的,由main发起调用,真正执行connnect的是nio线程,连接是需要时间的,可能连接还没有建立成功,就去调用channel,显然此时是没有channel的,发送数据的方法是有channel调用的,肯定是发送不了的
- 处理方式2:异步处理,由其他线程处理
//2.处理方式2:通过addListener异步处理
channelFuture.addListener(new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture channelFuture) throws Exception {
channelFuture.channel();
channel.writeAndFlush("async-msg...");
}
});
closeFuture谅解
@Slf4j
public class CloseFutureClient {
public static void main(String[] args) throws InterruptedException {
NioEventLoopGroup group = new NioEventLoopGroup();
//1. 启动类
ChannelFuture channelFuture = new Bootstrap()
//2. 添加EventLoop
.group(new NioEventLoopGroup())
//3. 选择客户端channel实现
.channel(NioSocketChannel.class)
//4. 添加处理器
.handler(new ChannelInitializer<NioSocketChannel>() {
@Override
//在连接建立后被调用
protected void initChannel(NioSocketChannel channel) throws Exception {
//编码器,将要发送的消息转为ByteBuf
channel.pipeline().addLast(new StringEncoder());
}
})
//5. 连接到服务器
.connect(new InetSocketAddress(8080));
//处理方式1:sync同步阻塞,等待建立连接
Channel channel = channelFuture
//阻塞方法,直到连接建立
.sync()
//代表连接对象
.channel();
new Thread(() -> {
Scanner scanner = new Scanner(System.in);
while (true) {
String s = scanner.nextLine();
if ("q".equals(s)) {
//close是异步的,是由nio线程执行的
channel.close();
//关闭之后的其他操作,但是不能在这里善后处理,因为close方法异步的,有可能close还没执行,就走到了关闭之后的操作
//解决:使用closeFuture来处理,方式1:同步 方式2:异步
//log.info("关闭之后的操作");
break;
}
channel.writeAndFlush(s);
}
}, "input").start();
ChannelFuture closeFuture = channel.closeFuture();
//方式1:同步,是在main线程中处理
/*closeFuture.sync();
//关闭之后的操作
log.info("同步关闭之后的操作");
group.shutdownGracefully();*///优雅关闭客户端,停止java
//方式2:异步,是在nio线程里处理
closeFuture.addListener(new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture channelFuture) throws Exception {
log.info("异步关闭之后的操作");
group.shutdownGracefully();//优雅关闭客户端,停止java
}
});
}
}
观察结果:
//方式1,看到是main
08:46:52.171 [main] INFO com.jpy.netty.c2.CloseFutureClient - 同步关闭之后的操作
//方式1看到思nio
08:53:35.956 [nioEventLoopGroup-2-1] INFO com.jpy.netty.c2.CloseFutureClient - 异步关闭之后的操作
注意点:
- close方法是在nio线程中执行的,所以不能在close调用后直接进行善后处理,这样善后处理是在new Thread里执行,两个线程无法保障顺序
- 方式1:同步,善后处理是在main中执行
- 方式2:异步,善后处理是在nio线程中