Netty 中所有的 I/O 操作都是异步的。
JDK 预置了 interface java.util.concurrent.Future,Future 提供了一种在操作完成时通知应用程序的方式。这个对象可以看作是一个异步操作的结果的占位符;它将在未来的某个时刻完成,并提供对其结果的访问。但是其所提供的实现,只允许手动检查对应的操作是否已经完成,或者一直阻塞直到它完成。这是非常繁琐的,所以 Netty 提供了它自己的实现ChannelFuture,用于在执行异步操作的时候使用。
每个 Netty 的出站 I/O 操作都将返回一个 ChannelFuture。

常见的方法有

  • Channel channel(),返回当前正在进行 IO 操作的通道
  • ChannelFuture sync(),等待异步操作执行完毕。异步非阻塞,main发起了调用,真正执行connect的是NioEventLoopGroup中的线程


客户端代码


  1. new Bootstrap()
  2. .group(new NioEventLoopGroup())
  3. .channel(NioSocketChannel.class)
  4. .handler(new ChannelInitializer<Channel>() {
  5. @Override
  6. protected void initChannel(Channel ch) {
  7. ch.pipeline().addLast(new StringEncoder());
  8. }
  9. })
  10. .connect("127.0.0.1", 8080)
  11. .sync()
  12. .channel()
  13. .writeAndFlush(new Date() + ": hello world!");

现在把它拆开来看

  1. ChannelFuture channelFuture = new Bootstrap()
  2. .group(new NioEventLoopGroup())
  3. .channel(NioSocketChannel.class)
  4. .handler(new ChannelInitializer<Channel>() {
  5. @Override
  6. protected void initChannel(Channel ch) {
  7. ch.pipeline().addLast(new StringEncoder());
  8. }
  9. })
  10. .connect("127.0.0.1", 8080); // 1
  11. channelFuture.sync().channel().writeAndFlush(new Date() + ": hello world!");
  • 1 处返回的是 ChannelFuture 对象,它的作用是利用 channel() 方法来获取 Channel 对象

注意:connect 方法是异步的,意味着不等连接建立,方法执行就返回了。因此 channelFuture 对象中不能【立刻】获得到正确的 Channel 对象

实验如下:

  1. ChannelFuture channelFuture = new Bootstrap()
  2. .group(new NioEventLoopGroup())
  3. .channel(NioSocketChannel.class)
  4. .handler(new ChannelInitializer<Channel>() {
  5. @Override
  6. protected void initChannel(Channel ch) {
  7. ch.pipeline().addLast(new StringEncoder());
  8. }
  9. })
  10. .connect("127.0.0.1", 8080);
  11. System.out.println(channelFuture.channel()); // 1
  12. channelFuture.sync(); // 2
  13. System.out.println(channelFuture.channel()); // 3
  • 执行到 1 时,连接未建立,打印 [id: 0x2e1884dd]
  • 执行到 2 时,sync 方法是同步等待连接建立完成
  • 执行到 3 时,连接肯定建立了,打印 [id: 0x2e1884dd, L:/127.0.0.1:57191 - R:/127.0.0.1:8080]

除了用 sync 方法可以让异步操作同步以外,还可以使用回调的方式:

  1. ChannelFuture channelFuture = new Bootstrap()
  2. .group(new NioEventLoopGroup())
  3. .channel(NioSocketChannel.class)
  4. .handler(new ChannelInitializer<Channel>() {
  5. @Override
  6. protected void initChannel(Channel ch) {
  7. ch.pipeline().addLast(new StringEncoder());
  8. }
  9. })
  10. .connect("127.0.0.1", 8080);
  11. System.out.println(channelFuture.channel()); // 1
  12. channelFuture.addListener((ChannelFutureListener) future -> {
  13. System.out.println(future.channel()); // 2 nio线程调用
  14. });