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线程中