Netty之future和Channelfuture Netty之future和Channelfuture

Netty之future和Channelfuture


Future,在Netty中所有的IO操作都是异步的,因此,你不能立刻得知消息是否被正确处理,但是我们可以过一会等它执行完成或者直接注册一个监听,具体的实现就是通过Future和ChannelFuture,他们可以注册一个监听,当操作执行成功或失败时监听会自动触发。总之,所有的操作都会返回一个ChannelFuture。

Netty中的异步,就不得不提ChannelFuture。Netty中的IO操作是异步的,包括bind、write、connect等操作会简单的返回一个ChannelFuture,调用者并不能立刻获得结果。

在netty中所有的io操作都是异步的,也就是说我们在发送完消息后,netty内部是采用线程池去处理,方法立即返回了,但有时候我们需要外部方法等待服务器的响应,整个过程需要同步处理,那么就需要将异步调用转为同步调用,原理很简单,就是在调用异步方法后,主线程阻塞,直到异步方法返回结果

 在netty中所有的I/O操作都是异步,这意味着netty提供的I/O方法调用都将立即返回,会返回一个ChannelFuture对象的实像,它将会给你一些信息,关于I/O执行状态的结果,但此时不能保证真正的I/O操作已经完成。

推荐使用addListener(ChannelFutureListener)异步得到通知当一个I/O操作完成后,做任何后续任务,而不是通过调用await方法(降低吞吐量)。但如果你想要业务场景是必须先执行A,然后同步执行B(异步通知不合适的场景),使用await是比较方便的。但await有一个限制,调用await方法的线程不能是I/O 线程(work线程),否则会抛出一个异常,避免死锁。

作为一个异步NIO框架,Netty的所有IO操作都是异步非阻塞的,通过Future-Listener机制,用户可以方便的主动获取或者通过通知机制获得IO操作结果。

比如:

  1.      /**
  2.      * Connect a {@link Channel} to the remote peer.
  3.      */
  4.      public ChannelFuture connect(String inetHost, int inetPort) {
  5.          return connect( new InetSocketAddress(inetHost, inetPort));
  6.     }

  1.      /**
  2.      * Create a new {@link Channel} and bind it.
  3.      */
  4.      public ChannelFuture bind(int inetPort) {
  5.          return bind( new InetSocketAddress(inetPort));
  6.     }

  1.      /**
  2.      * Request to write a message via this {@link Channel} through the {@link ChannelPipeline}.
  3.      * This method will not request to actual flush, so be sure to call {@link #flush()}
  4.      * once you want to request to flush all pending data to the actual transport.
  5.      */
  6.      ChannelFuture write(Object msg);

判断Future状态的方法

Future状态图

ChannelFuture对象状态只有uncompleted和completed。当一个I/O操作开始时,一个ChannelFuture实例被创建(我知道的暂时除close方法),刚开始时,future对象的实例即不是succeeded,failed,cancelled。因为真正的I/O操作还没有完成。如果正的I/O操作已经完成,那么future的状态将是completed,无论结果是succeeded,failed,cancelled。

netty中Future接口中的方法

netty的Future是继承自java.util.concurrent.Future接口

  1.      /**
  2.      * Returns {@code true} if and only if the I/O operation was completed
  3.      * successfully.
  4.      */
  5.      boolean isSuccess();
  6.      /**
  7.      * returns {@code true} if and only if the operation can be cancelled via {@link #cancel(boolean)}.
  8.      */
  9.      boolean isCancellable();

java.util.concurrent.Future接口中的方法:

  1.      /**
  2.      * Attempts to cancel execution of this task.  This attempt will
  3.      * fail if the task has already completed, has already been cancelled,
  4.      * or could not be cancelled for some other reason. If successful,
  5.      * and this task has not started when {@code cancel} is called,
  6.      * this task should never run.  If the task has already started,
  7.      * then the {@code mayInterruptIfRunning} parameter determines
  8.      * whether the thread executing this task should be interrupted in
  9.      * an attempt to stop the task.
  10.      *
  11.      * <p>After this method returns, subsequent calls to {@link #isDone} will
  12.      * always return {@code true}.  Subsequent calls to {@link #isCancelled}
  13.      * will always return {@code true} if this method returned {@code true}.
  14.      *
  15.      * @param mayInterruptIfRunning {@code true} if the thread executing this
  16.      * task should be interrupted; otherwise, in-progress tasks are allowed
  17.      * to complete
  18.      * @return {@code false} if the task could not be cancelled,
  19.      * typically because it has already completed normally;
  20.      * {@code true} otherwise
  21.      */
  22.      boolean cancel(boolean mayInterruptIfRunning);
  23.      /**
  24.      * Returns {@code true} if this task was cancelled before it completed
  25.      * normally.
  26.      *
  27.      * @return {@code true} if this task was cancelled before it completed
  28.      */
  29.      boolean isCancelled();
  30.      /**
  31.      * Returns {@code true} if this task completed.
  32.      *
  33.      * Completion may be due to normal termination, an exception, or
  34.      * cancellation -- in all of these cases, this method will return
  35.      * {@code true}.
  36.      *
  37.      * @return {@code true} if this task completed
  38.      */
  39.      boolean isDone();

维持netty中Future的生命周期的方法

sync()

syncUninterruptibly()

await()

await(long timeout, TimeUnit unit)

awaitUninterruptibly(long timeout, TimeUnit unit):

awaitUninterruptibly(long timeoutMillis);

  1.      /**
  2.      * Waits for this future until it is done, and rethrows the cause of the failure if this future
  3.      * failed.
  4.      */
  5.      Future<V> sync() throws InterruptedException;
  6.      /**
  7.      * Waits for this future until it is done, and rethrows the cause of the failure if this future
  8.      * failed.
  9.      */
  10.      Future<V> syncUninterruptibly();
  11.      /**
  12.      * Waits for this future to be completed.
  13.      *
  14.      * @throws InterruptedException
  15.      *         if the current thread was interrupted
  16.      */
  17.      Future<V> await() throws InterruptedException;
  18.      /**
  19.      * Waits for this future to be completed without
  20.      * interruption.  This method catches an {@link InterruptedException} and
  21.      * discards it silently.
  22.      */
  23.      Future<V> awaitUninterruptibly();
  24.      /**
  25.      * Waits for this future to be completed within the
  26.      * specified time limit.
  27.      *
  28.      * @return {@code true} if and only if the future was completed within
  29.      *         the specified time limit
  30.      *
  31.      * @throws InterruptedException
  32.      *         if the current thread was interrupted
  33.      */
  34.      boolean await(long timeout, TimeUnit unit) throws InterruptedException;
  35.      /**
  36.      * Waits for this future to be completed within the
  37.      * specified time limit.
  38.      *
  39.      * @return {@code true} if and only if the future was completed within
  40.      *         the specified time limit
  41.      *
  42.      * @throws InterruptedException
  43.      *         if the current thread was interrupted
  44.      */
  45.      boolean await(long timeoutMillis) throws InterruptedException;
  46.      /**
  47.      * Waits for this future to be completed within the
  48.      * specified time limit without interruption.  This method catches an
  49.      * {@link InterruptedException} and discards it silently.
  50.      *
  51.      * @return {@code true} if and only if the future was completed within
  52.      *         the specified time limit
  53.      */
  54.      boolean awaitUninterruptibly(long timeout, TimeUnit unit);
  55.      /**
  56.      * Waits for this future to be completed within the
  57.      * specified time limit without interruption.  This method catches an
  58.      * {@link InterruptedException} and discards it silently.
  59.      *
  60.      * @return {@code true} if and only if the future was completed within
  61.      *         the specified time limit
  62.      */
  63.      boolean awaitUninterruptibly(long timeoutMillis);

示例DEMO

服务器端代码

  1. package hello.netty.lyx.com;
  2. import io.netty.bootstrap.ServerBootstrap;
  3. import io.netty.channel.ChannelFuture;
  4. import io.netty.channel.ChannelInitializer;
  5. import io.netty.channel.ChannelOption;
  6. import io.netty.channel.EventLoopGroup;
  7. import io.netty.channel.nio.NioEventLoopGroup;
  8. import io.netty.channel.socket.SocketChannel;
  9. import io.netty.channel.socket.nio.NioServerSocketChannel;
  10. public  class HelloServer {
  11.      public void start(int port) throws Exception {
  12.         EventLoopGroup bossGroup =  new NioEventLoopGroup();
  13.         EventLoopGroup workerGroup =  new NioEventLoopGroup();
  14.          try {
  15.             ServerBootstrap b =  new ServerBootstrap();
  16.             b.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class)
  17.                     .childHandler( new ChannelInitializer<SocketChannel>() {
  18.                          @Override
  19.                          public void initChannel(SocketChannel ch)
  20.                                  throws Exception {
  21.                              // 注册handler
  22.                             ch.pipeline().addLast( new HelloServerInHandler());
  23.                         }
  24.                     }).option(ChannelOption.SO_BACKLOG,  128)
  25.                     .childOption(ChannelOption.SO_KEEPALIVE,  true);
  26.              long t1 = System.currentTimeMillis();
  27.             ChannelFuture f = b.bind(port).sync();
  28.             f.channel().closeFuture().sync();
  29.              long t2 = System.currentTimeMillis();
  30.             System.out.print( "diff in seconds:" + (t2 - t1) /  1000 +  "\n");
  31.         }  finally {
  32.             workerGroup.shutdownGracefully();
  33.             bossGroup.shutdownGracefully();
  34.         }
  35.     }
  36.      public static void main(String[] args) throws Exception {
  37.         HelloServer server =  new HelloServer();
  38.         server.start( 9090);
  39.     }
  40. }

  1. package hello.netty.lyx.com;
  2. import io.netty.buffer.ByteBuf;
  3. import io.netty.channel.ChannelHandlerContext;
  4. import io.netty.channel.ChannelInboundHandlerAdapter;
  5. // 该handler是InboundHandler类型
  6. public  class HelloServerInHandler extends ChannelInboundHandlerAdapter {
  7.      @Override
  8.      public boolean isSharable() {
  9.         System.out.println( "==============handler-sharable==============");
  10.          return  super.isSharable();
  11.     }
  12.      @Override
  13.      public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
  14.         System.out.println( "==============channel-register==============");
  15.     }
  16.      @Override
  17.      public void channelUnregistered(ChannelHandlerContext ctx) throws Exception {
  18.         System.out.println( "==============channel-unregister==============");
  19.     }
  20.      @Override
  21.      public void channelActive(ChannelHandlerContext ctx) throws Exception {
  22.         System.out.println( "==============channel-active==============");
  23.     }
  24.      @Override
  25.      public void channelInactive(ChannelHandlerContext ctx) throws Exception {
  26.         System.out.println( "==============channel-inactive==============");
  27.     }
  28.      @Override
  29.      public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
  30.         System.out.println( "==============channel-read==============");
  31.         ByteBuf result = (ByteBuf) msg;
  32.          byte[] result1 =  new  byte[result.readableBytes()];
  33.          // msg中存储的是ByteBuf类型的数据,把数据读取到byte[]中
  34.         result.readBytes(result1);
  35.         String resultStr =  new String(result1);
  36.          // 接收并打印客户端的信息
  37.         System.out.println( "Client said:" + resultStr);
  38.          // 释放资源,这行很关键
  39.         result.release();
  40.          // 向客户端发送消息
  41.         String response =  "I am ok!";
  42.          // 在当前场景下,发送的数据必须转换成ByteBuf数组
  43.         ByteBuf encoded = ctx.alloc().buffer( 4 * response.length());
  44.         encoded.writeBytes(response.getBytes());
  45.         ctx.writeAndFlush(encoded);
  46.         Thread.sleep( 10000);
  47.         System.out.println( "thread sleep end");
  48.         ctx.close();
  49. //        Thread.sleep(10000);
  50. //        System.out.println("thread sleep end");
  51.     }
  52.      @Override
  53.      public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
  54.         System.out.println( "==============channel-read-complete==============");
  55.         ctx.flush();
  56.     }
  57. }

客户端代码

  1. package hello.netty.lyx.com;
  2. import io.netty.bootstrap.Bootstrap;
  3. import io.netty.channel.ChannelFuture;
  4. import io.netty.channel.ChannelInitializer;
  5. import io.netty.channel.ChannelOption;
  6. import io.netty.channel.EventLoopGroup;
  7. import io.netty.channel.nio.NioEventLoopGroup;
  8. import io.netty.channel.socket.SocketChannel;
  9. import io.netty.channel.socket.nio.NioSocketChannel;
  10. /**
  11.  * 1、Client向Server发送消息:Are you ok?
  12.  * 2、Server接收客户端发送的消息,并打印出来。
  13.  * 3、Server端向客户端发送消息:I am ok!
  14.  * 4、Client接收Server端发送的消息,并打印出来,通讯结束。
  15.  */
  16. public  class HelloClient {
  17.      public void connect(String host, int port) throws Exception {
  18.         EventLoopGroup workerGroup =  new NioEventLoopGroup();
  19.          try {
  20.             Bootstrap b =  new Bootstrap();
  21.             b.group(workerGroup);
  22.             b.channel(NioSocketChannel.class);
  23.             b.option(ChannelOption.SO_KEEPALIVE,  true);
  24.             b.handler( new ChannelInitializer<SocketChannel>() {
  25.                  @Override
  26.                  public void initChannel(SocketChannel ch) throws Exception {
  27.                     ch.pipeline().addLast( new HelloClientIntHandler());
  28.                 }
  29.             });
  30.              // Start the client.
  31.              /**
  32.              * wait()方法:Waits for this future to be completed.
  33.              * Waits for this future until it is done, and rethrows the cause of the failure if this future
  34.              * failed.
  35.              */
  36.              long t1 = System.currentTimeMillis();
  37.             ChannelFuture f = b.connect(host, port).await();
  38.              // Wait until the connection is closed.
  39.             f.channel().closeFuture().await();     //closeFuture方法返回通道关闭的结果
  40.              long t2 = System.currentTimeMillis();
  41.             System.out.print( "diff in seconds:" + (t2 - t1) /  1000 +  "\n");
  42.         }  finally {
  43.             workerGroup.shutdownGracefully();
  44.         }
  45.     }
  46.      public static void main(String[] args) throws Exception {
  47.         HelloClient client =  new HelloClient();
  48.         client.connect( "127.0.0.1"9090);
  49.     }
  50. }

  1. package hello.netty.lyx.com;
  2. import io.netty.buffer.ByteBuf;
  3. import io.netty.channel.ChannelHandlerContext;
  4. import io.netty.channel.ChannelInboundHandlerAdapter;
  5. //InboundHandler类型
  6. public  class HelloClientIntHandler extends ChannelInboundHandlerAdapter {
  7.      @Override
  8.      public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
  9.         System.out.println( "==============channel--register==============");
  10.     }
  11.      @Override
  12.      public void channelUnregistered(ChannelHandlerContext ctx) throws Exception {
  13.         System.out.println( "==============channel--unregistered==============");
  14.     }
  15.      @Override
  16.      public void channelInactive(ChannelHandlerContext ctx) throws Exception {
  17.         System.out.println( "==============channel--inactive==============");
  18.     }
  19.      // 连接成功后,向server发送消息
  20.      @Override
  21.      public void channelActive(ChannelHandlerContext ctx) throws Exception {
  22.         System.out.println( "==============channel--active==============");
  23.         String msg =  "Are you ok?";
  24.          /**
  25.          * 分配ByteBuf
  26.          * Return the assigned {@link io.netty.buffer.ByteBufAllocator} which will be used to allocate {@link ByteBuf}s.
  27.          */
  28.         ByteBuf encoded = ctx.alloc().buffer( 4 * msg.length());
  29.         encoded.writeBytes(msg.getBytes());
  30.         ctx.write(encoded);
  31.         ctx.flush();
  32.     }
  33.      // 接收server端的消息,并打印出来
  34.      @Override
  35.      public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
  36.         System.out.println( "==============channel--read==============");
  37.          //先等待两秒
  38.         Thread.sleep( 2000);
  39.         ByteBuf result = (ByteBuf) msg;
  40.          byte[] result1 =  new  byte[result.readableBytes()];
  41.         result.readBytes(result1);
  42.         System.out.println( "Server said:" +  new String(result1));
  43.         result.release();
  44.     }
  45. }

客户端的异步IO

让这个demo异步方式运行则客户端的代码应该是这样的:

  1. long t1 = System.currentTimeMillis();
  2. ChannelFuture f = b.connect(host, port).await();
  3. long t2 = System.currentTimeMillis();
  4. System.out.print( "diff in seconds:" + (t2 - t1) /  1000 +  "\n");

看运行结果:

==============channel–register==============

diff in seconds:0

==============channel–active==============

==============channel–inactive==============

==============channel–unregistered==============

和原来的代码相比,通过运行结果可以分析出没有read服务器的数据。

在看一段异步的代码:

  1.              long t1 = System.currentTimeMillis();
  2.             ChannelFuture f = b.connect(host, port).await();
  3.             f = f.channel().closeFuture();
  4.             f.addListener( new ChannelFutureListener() {
  5.                  @Override
  6.                  public void operationComplete(ChannelFuture future) throws Exception {
  7.                     System.out.println( "success complete!!ok!!");
  8.                 }
  9.             });
  10.              long t2 = System.currentTimeMillis();
  11.             System.out.print( "diff in seconds:" + (t2 - t1) /  1000 +  "\n");

运行结果:

==============channel–register==============

==============channel–active==============

diff in seconds:0

success complete!!ok!!

==============channel–inactive==============

==============channel–unregistered==============

给通道的关闭Future注册了监听事件,监听事件等这个关闭Future完成后打印了字符串,而客户端没有读取服务器的数据。

在看一段代码

  1.              long t1 = System.currentTimeMillis();
  2.             ChannelFuture f = b.connect(host, port).await();
  3.             f = f.channel().closeFuture().await();
  4.             f.addListener( new ChannelFutureListener() {
  5.                  @Override
  6.                  public void operationComplete(ChannelFuture future) throws Exception {
  7.                     System.out.println( "success complete!!ok!!");
  8.                 }
  9.             });
  10.              long t2 = System.currentTimeMillis();
  11.             System.out.print( "diff in seconds:" + (t2 - t1) /  1000 +  "\n");

运行结果:

==============channel–register==============

==============channel–active==============

==============channel–read==============

Server said:I am ok!

==============channel–inactive==============

==============channel–unregistered==============

diff in seconds:2

success complete!!ok!!

可以读取服务器的数据,并且监听事件也起了作用,但这不是一个异步调用。

文章标签: Netty

Future,在Netty中所有的IO操作都是异步的,因此,你不能立刻得知消息是否被正确处理,但是我们可以过一会等它执行完成或者直接注册一个监听,具体的实现就是通过Future和ChannelFuture,他们可以注册一个监听,当操作执行成功或失败时监听会自动触发。总之,所有的操作都会返回一个ChannelFuture。

Netty中的异步,就不得不提ChannelFuture。Netty中的IO操作是异步的,包括bind、write、connect等操作会简单的返回一个ChannelFuture,调用者并不能立刻获得结果。

在netty中所有的io操作都是异步的,也就是说我们在发送完消息后,netty内部是采用线程池去处理,方法立即返回了,但有时候我们需要外部方法等待服务器的响应,整个过程需要同步处理,那么就需要将异步调用转为同步调用,原理很简单,就是在调用异步方法后,主线程阻塞,直到异步方法返回结果

 在netty中所有的I/O操作都是异步,这意味着netty提供的I/O方法调用都将立即返回,会返回一个ChannelFuture对象的实像,它将会给你一些信息,关于I/O执行状态的结果,但此时不能保证真正的I/O操作已经完成。

推荐使用addListener(ChannelFutureListener)异步得到通知当一个I/O操作完成后,做任何后续任务,而不是通过调用await方法(降低吞吐量)。但如果你想要业务场景是必须先执行A,然后同步执行B(异步通知不合适的场景),使用await是比较方便的。但await有一个限制,调用await方法的线程不能是I/O 线程(work线程),否则会抛出一个异常,避免死锁。

作为一个异步NIO框架,Netty的所有IO操作都是异步非阻塞的,通过Future-Listener机制,用户可以方便的主动获取或者通过通知机制获得IO操作结果。

比如:

  1.      /**
  2.      * Connect a {@link Channel} to the remote peer.
  3.      */
  4.      public ChannelFuture connect(String inetHost, int inetPort) {
  5.          return connect( new InetSocketAddress(inetHost, inetPort));
  6.     }

  1.      /**
  2.      * Create a new {@link Channel} and bind it.
  3.      */
  4.      public ChannelFuture bind(int inetPort) {
  5.          return bind( new InetSocketAddress(inetPort));
  6.     }

  1.      /**
  2.      * Request to write a message via this {@link Channel} through the {@link ChannelPipeline}.
  3.      * This method will not request to actual flush, so be sure to call {@link #flush()}
  4.      * once you want to request to flush all pending data to the actual transport.
  5.      */
  6.      ChannelFuture write(Object msg);

判断Future状态的方法

Future状态图

ChannelFuture对象状态只有uncompleted和completed。当一个I/O操作开始时,一个ChannelFuture实例被创建(我知道的暂时除close方法),刚开始时,future对象的实例即不是succeeded,failed,cancelled。因为真正的I/O操作还没有完成。如果正的I/O操作已经完成,那么future的状态将是completed,无论结果是succeeded,failed,cancelled。

netty中Future接口中的方法

netty的Future是继承自java.util.concurrent.Future接口

  1.      /**
  2.      * Returns {@code true} if and only if the I/O operation was completed
  3.      * successfully.
  4.      */
  5.      boolean isSuccess();
  6.      /**
  7.      * returns {@code true} if and only if the operation can be cancelled via {@link #cancel(boolean)}.
  8.      */
  9.      boolean isCancellable();

java.util.concurrent.Future接口中的方法:

  1.      /**
  2.      * Attempts to cancel execution of this task.  This attempt will
  3.      * fail if the task has already completed, has already been cancelled,
  4.      * or could not be cancelled for some other reason. If successful,
  5.      * and this task has not started when {@code cancel} is called,
  6.      * this task should never run.  If the task has already started,
  7.      * then the {@code mayInterruptIfRunning} parameter determines
  8.      * whether the thread executing this task should be interrupted in
  9.      * an attempt to stop the task.
  10.      *
  11.      * <p>After this method returns, subsequent calls to {@link #isDone} will
  12.      * always return {@code true}.  Subsequent calls to {@link #isCancelled}
  13.      * will always return {@code true} if this method returned {@code true}.
  14.      *
  15.      * @param mayInterruptIfRunning {@code true} if the thread executing this
  16.      * task should be interrupted; otherwise, in-progress tasks are allowed
  17.      * to complete
  18.      * @return {@code false} if the task could not be cancelled,
  19.      * typically because it has already completed normally;
  20.      * {@code true} otherwise
  21.      */
  22.      boolean cancel(boolean mayInterruptIfRunning);
  23.      /**
  24.      * Returns {@code true} if this task was cancelled before it completed
  25.      * normally.
  26.      *
  27.      * @return {@code true} if this task was cancelled before it completed
  28.      */
  29.      boolean isCancelled();
  30.      /**
  31.      * Returns {@code true} if this task completed.
  32.      *
  33.      * Completion may be due to normal termination, an exception, or
  34.      * cancellation -- in all of these cases, this method will return
  35.      * {@code true}.
  36.      *
  37.      * @return {@code true} if this task completed
  38.      */
  39.      boolean isDone();

维持netty中Future的生命周期的方法

sync()

syncUninterruptibly()

await()

await(long timeout, TimeUnit unit)

awaitUninterruptibly(long timeout, TimeUnit unit):

awaitUninterruptibly(long timeoutMillis);

  1.      /**
  2.      * Waits for this future until it is done, and rethrows the cause of the failure if this future
  3.      * failed.
  4.      */
  5.      Future<V> sync() throws InterruptedException;
  6.      /**
  7.      * Waits for this future until it is done, and rethrows the cause of the failure if this future
  8.      * failed.
  9.      */
  10.      Future<V> syncUninterruptibly();
  11.      /**
  12.      * Waits for this future to be completed.
  13.      *
  14.      * @throws InterruptedException
  15.      *         if the current thread was interrupted
  16.      */
  17.      Future<V> await() throws InterruptedException;
  18.      /**
  19.      * Waits for this future to be completed without
  20.      * interruption.  This method catches an {@link InterruptedException} and
  21.      * discards it silently.
  22.      */
  23.      Future<V> awaitUninterruptibly();
  24.      /**
  25.      * Waits for this future to be completed within the
  26.      * specified time limit.
  27.      *
  28.      * @return {@code true} if and only if the future was completed within
  29.      *         the specified time limit
  30.      *
  31.      * @throws InterruptedException
  32.      *         if the current thread was interrupted
  33.      */
  34.      boolean await(long timeout, TimeUnit unit) throws InterruptedException;
  35.      /**
  36.      * Waits for this future to be completed within the
  37.      * specified time limit.
  38.      *
  39.      * @return {@code true} if and only if the future was completed within
  40.      *         the specified time limit
  41.      *
  42.      * @throws InterruptedException
  43.      *         if the current thread was interrupted
  44.      */
  45.      boolean await(long timeoutMillis) throws InterruptedException;
  46.      /**
  47.      * Waits for this future to be completed within the
  48.      * specified time limit without interruption.  This method catches an
  49.      * {@link InterruptedException} and discards it silently.
  50.      *
  51.      * @return {@code true} if and only if the future was completed within
  52.      *         the specified time limit
  53.      */
  54.      boolean awaitUninterruptibly(long timeout, TimeUnit unit);
  55.      /**
  56.      * Waits for this future to be completed within the
  57.      * specified time limit without interruption.  This method catches an
  58.      * {@link InterruptedException} and discards it silently.
  59.      *
  60.      * @return {@code true} if and only if the future was completed within
  61.      *         the specified time limit
  62.      */
  63.      boolean awaitUninterruptibly(long timeoutMillis);

示例DEMO

服务器端代码

  1. package hello.netty.lyx.com;
  2. import io.netty.bootstrap.ServerBootstrap;
  3. import io.netty.channel.ChannelFuture;
  4. import io.netty.channel.ChannelInitializer;
  5. import io.netty.channel.ChannelOption;
  6. import io.netty.channel.EventLoopGroup;
  7. import io.netty.channel.nio.NioEventLoopGroup;
  8. import io.netty.channel.socket.SocketChannel;
  9. import io.netty.channel.socket.nio.NioServerSocketChannel;
  10. public  class HelloServer {
  11.      public void start(int port) throws Exception {
  12.         EventLoopGroup bossGroup =  new NioEventLoopGroup();
  13.         EventLoopGroup workerGroup =  new NioEventLoopGroup();
  14.          try {
  15.             ServerBootstrap b =  new ServerBootstrap();
  16.             b.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class)
  17.                     .childHandler( new ChannelInitializer<SocketChannel>() {
  18.                          @Override
  19.                          public void initChannel(SocketChannel ch)
  20.                                  throws Exception {
  21.                              // 注册handler
  22.                             ch.pipeline().addLast( new HelloServerInHandler());
  23.                         }
  24.                     }).option(ChannelOption.SO_BACKLOG,  128)
  25.                     .childOption(ChannelOption.SO_KEEPALIVE,  true);
  26.              long t1 = System.currentTimeMillis();
  27.             ChannelFuture f = b.bind(port).sync();
  28.             f.channel().closeFuture().sync();
  29.              long t2 = System.currentTimeMillis();
  30.             System.out.print( "diff in seconds:" + (t2 - t1) /  1000 +  "\n");
  31.         }  finally {
  32.             workerGroup.shutdownGracefully();
  33.             bossGroup.shutdownGracefully();
  34.         }
  35.     }
  36.      public static void main(String[] args) throws Exception {
  37.         HelloServer server =  new HelloServer();
  38.         server.start( 9090);
  39.     }
  40. }

  1. package hello.netty.lyx.com;
  2. import io.netty.buffer.ByteBuf;
  3. import io.netty.channel.ChannelHandlerContext;
  4. import io.netty.channel.ChannelInboundHandlerAdapter;
  5. // 该handler是InboundHandler类型
  6. public  class HelloServerInHandler extends ChannelInboundHandlerAdapter {
  7.      @Override
  8.      public boolean isSharable() {
  9.         System.out.println( "==============handler-sharable==============");
  10.          return  super.isSharable();
  11.     }
  12.      @Override
  13.      public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
  14.         System.out.println( "==============channel-register==============");
  15.     }
  16.      @Override
  17.      public void channelUnregistered(ChannelHandlerContext ctx) throws Exception {
  18.         System.out.println( "==============channel-unregister==============");
  19.     }
  20.      @Override
  21.      public void channelActive(ChannelHandlerContext ctx) throws Exception {
  22.         System.out.println( "==============channel-active==============");
  23.     }
  24.      @Override
  25.      public void channelInactive(ChannelHandlerContext ctx) throws Exception {
  26.         System.out.println( "==============channel-inactive==============");
  27.     }
  28.      @Override
  29.      public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
  30.         System.out.println( "==============channel-read==============");
  31.         ByteBuf result = (ByteBuf) msg;
  32.          byte[] result1 =  new  byte[result.readableBytes()];
  33.          // msg中存储的是ByteBuf类型的数据,把数据读取到byte[]中
  34.         result.readBytes(result1);
  35.         String resultStr =  new String(result1);
  36.          // 接收并打印客户端的信息
  37.         System.out.println( "Client said:" + resultStr);
  38.          // 释放资源,这行很关键
  39.         result.release();
  40.          // 向客户端发送消息
  41.         String response =  "I am ok!";
  42.          // 在当前场景下,发送的数据必须转换成ByteBuf数组
  43.         ByteBuf encoded = ctx.alloc().buffer( 4 * response.length());
  44.         encoded.writeBytes(response.getBytes());
  45.         ctx.writeAndFlush(encoded);
  46.         Thread.sleep( 10000);
  47.         System.out.println( "thread sleep end");
  48.         ctx.close();
  49. //        Thread.sleep(10000);
  50. //        System.out.println("thread sleep end");
  51.     }
  52.      @Override
  53.      public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
  54.         System.out.println( "==============channel-read-complete==============");
  55.         ctx.flush();
  56.     }
  57. }

客户端代码

  1. package hello.netty.lyx.com;
  2. import io.netty.bootstrap.Bootstrap;
  3. import io.netty.channel.ChannelFuture;
  4. import io.netty.channel.ChannelInitializer;
  5. import io.netty.channel.ChannelOption;
  6. import io.netty.channel.EventLoopGroup;
  7. import io.netty.channel.nio.NioEventLoopGroup;
  8. import io.netty.channel.socket.SocketChannel;
  9. import io.netty.channel.socket.nio.NioSocketChannel;
  10. /**
  11.  * 1、Client向Server发送消息:Are you ok?
  12.  * 2、Server接收客户端发送的消息,并打印出来。
  13.  * 3、Server端向客户端发送消息:I am ok!
  14.  * 4、Client接收Server端发送的消息,并打印出来,通讯结束。
  15.  */
  16. public  class HelloClient {
  17.      public void connect(String host, int port) throws Exception {
  18.         EventLoopGroup workerGroup =  new NioEventLoopGroup();
  19.          try {
  20.             Bootstrap b =  new Bootstrap();
  21.             b.group(workerGroup);
  22.             b.channel(NioSocketChannel.class);
  23.             b.option(ChannelOption.SO_KEEPALIVE,  true);
  24.             b.handler( new ChannelInitializer<SocketChannel>() {
  25.                  @Override
  26.                  public void initChannel(SocketChannel ch) throws Exception {
  27.                     ch.pipeline().addLast( new HelloClientIntHandler());
  28.                 }
  29.             });
  30.              // Start the client.
  31.              /**
  32.              * wait()方法:Waits for this future to be completed.
  33.              * Waits for this future until it is done, and rethrows the cause of the failure if this future
  34.              * failed.
  35.              */
  36.              long t1 = System.currentTimeMillis();
  37.             ChannelFuture f = b.connect(host, port).await();
  38.              // Wait until the connection is closed.
  39.             f.channel().closeFuture().await();     //closeFuture方法返回通道关闭的结果
  40.              long t2 = System.currentTimeMillis();
  41.             System.out.print( "diff in seconds:" + (t2 - t1) /  1000 +  "\n");
  42.         }  finally {
  43.             workerGroup.shutdownGracefully();
  44.         }
  45.     }
  46.      public static void main(String[] args) throws Exception {
  47.         HelloClient client =  new HelloClient();
  48.         client.connect( "127.0.0.1"9090);
  49.     }
  50. }

  1. package hello.netty.lyx.com;
  2. import io.netty.buffer.ByteBuf;
  3. import io.netty.channel.ChannelHandlerContext;
  4. import io.netty.channel.ChannelInboundHandlerAdapter;
  5. //InboundHandler类型
  6. public  class HelloClientIntHandler extends ChannelInboundHandlerAdapter {
  7.      @Override
  8.      public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
  9.         System.out.println( "==============channel--register==============");
  10.     }
  11.      @Override
  12.      public void channelUnregistered(ChannelHandlerContext ctx) throws Exception {
  13.         System.out.println( "==============channel--unregistered==============");
  14.     }
  15.      @Override
  16.      public void channelInactive(ChannelHandlerContext ctx) throws Exception {
  17.         System.out.println( "==============channel--inactive==============");
  18.     }
  19.      // 连接成功后,向server发送消息
  20.      @Override
  21.      public void channelActive(ChannelHandlerContext ctx) throws Exception {
  22.         System.out.println( "==============channel--active==============");
  23.         String msg =  "Are you ok?";
  24.          /**
  25.          * 分配ByteBuf
  26.          * Return the assigned {@link io.netty.buffer.ByteBufAllocator} which will be used to allocate {@link ByteBuf}s.
  27.          */
  28.         ByteBuf encoded = ctx.alloc().buffer( 4 * msg.length());
  29.         encoded.writeBytes(msg.getBytes());
  30.         ctx.write(encoded);
  31.         ctx.flush();
  32.     }
  33.      // 接收server端的消息,并打印出来
  34.      @Override
  35.      public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
  36.         System.out.println( "==============channel--read==============");
  37.          //先等待两秒
  38.         Thread.sleep( 2000);
  39.         ByteBuf result = (ByteBuf) msg;
  40.          byte[] result1 =  new  byte[result.readableBytes()];
  41.         result.readBytes(result1);
  42.         System.out.println( "Server said:" +  new String(result1));
  43.         result.release();
  44.     }
  45. }

客户端的异步IO

让这个demo异步方式运行则客户端的代码应该是这样的:

  1. long t1 = System.currentTimeMillis();
  2. ChannelFuture f = b.connect(host, port).await();
  3. long t2 = System.currentTimeMillis();
  4. System.out.print( "diff in seconds:" + (t2 - t1) /  1000 +  "\n");

看运行结果:

==============channel–register==============

diff in seconds:0

==============channel–active==============

==============channel–inactive==============

==============channel–unregistered==============

和原来的代码相比,通过运行结果可以分析出没有read服务器的数据。

在看一段异步的代码:

  1.              long t1 = System.currentTimeMillis();
  2.             ChannelFuture f = b.connect(host, port).await();
  3.             f = f.channel().closeFuture();
  4.             f.addListener( new ChannelFutureListener() {
  5.                  @Override
  6.                  public void operationComplete(ChannelFuture future) throws Exception {
  7.                     System.out.println( "success complete!!ok!!");
  8.                 }
  9.             });
  10.              long t2 = System.currentTimeMillis();
  11.             System.out.print( "diff in seconds:" + (t2 - t1) /  1000 +  "\n");

运行结果:

==============channel–register==============

==============channel–active==============

diff in seconds:0

success complete!!ok!!

==============channel–inactive==============

==============channel–unregistered==============

给通道的关闭Future注册了监听事件,监听事件等这个关闭Future完成后打印了字符串,而客户端没有读取服务器的数据。

在看一段代码

  1.              long t1 = System.currentTimeMillis();
  2.             ChannelFuture f = b.connect(host, port).await();
  3.             f = f.channel().closeFuture().await();
  4.             f.addListener( new ChannelFutureListener() {
  5.                  @Override
  6.                  public void operationComplete(ChannelFuture future) throws Exception {
  7.                     System.out.println( "success complete!!ok!!");
  8.                 }
  9.             });
  10.              long t2 = System.currentTimeMillis();
  11.             System.out.print( "diff in seconds:" + (t2 - t1) /  1000 +  "\n");

运行结果:

==============channel–register==============

==============channel–active==============

==============channel–read==============

Server said:I am ok!

==============channel–inactive==============

==============channel–unregistered==============

diff in seconds:2

success complete!!ok!!

可以读取服务器的数据,并且监听事件也起了作用,但这不是一个异步调用。

猜你喜欢

转载自blog.csdn.net/tuxedolinux/article/details/80916859