Java Netty 学习(六) - NIO基础知识AIO

版权声明:本博客所有的原创文章,转载请注明出处,作者皆保留版权。 https://blog.csdn.net/anLA_/article/details/79679107

AIO是什么?
AIO是Java7出来的新东西,是对原有NIO的一种补充,
前面写到的内容已经和NIO,BIO比较过:Java Netty 学习(三)- BIO,AIO,NIO深入浅出

AIO介绍

在NIO编程时,会用到Selector,就是轮询,从而判断哪个channel可以使用。
而在AIO编程中,并不会用到Selector,它的可伸缩性更好,当有相应事件时,由系统调用提醒,可以理解为回调函数,从而Java程序员只需要把一些事件代码写好就可以了。

再打个比方,或许都用过ajax,以及用过jquery的$.post,记得这个方法都会有好几个方法,通过调用返回的状态来确定的。
AIO也是这样。

AIO中,主要有4个比较重要的异步类:

  • AsynchronousSocketChannel
  • AsynchronousServerSocketChannel
  • AsynchronousFileChannel
  • AsynchronousByteChannel

CompletionHandler接口

这个接口就两个方法,成功和失败,可以用于connect,read,write,accept等:

public interface CompletionHandler<V,A> {
    //调用成功
    void completed(V result, A attachment);

    //调用失败
    void failed(Throwable exc, A attachment);
}

例子

看个AsynchronousSocketChannel和AsynchronousServerSocketChannel的例子,助于理解:
AIOServer:

public class AIOServer {
    private AsynchronousServerSocketChannel server ;
    private Object attachment;

    public AIOServer(){
        try {
            server = AsynchronousServerSocketChannel.open().bind(new InetSocketAddress("127.0.0.1", 8088));
            System.out.println("server run at:127.0.0.1:8088");
        } catch (IOException e) {
            e.printStackTrace();
        }
        server.accept(attachment, new CompletionHandler<AsynchronousSocketChannel, Object>() {
            final ByteBuffer buffer = ByteBuffer.allocate(1024);
            Future<Integer> writeResult = null;    //定义一个异步任务,用于检验回写
            @Override
            public void completed(AsynchronousSocketChannel channel, Object attachment) {
                try {
                    //代表成功拿到了一个
                    buffer.clear();
                    channel.read(buffer).get(100, TimeUnit.SECONDS);    //把result里面东西,读到buffer里面。有超时的读取。
                    System.out.println("server read the data from client: " + new String(buffer.array()));
                    buffer.flip();
                    writeResult = channel.write(buffer);
                } catch (Exception e) {
                    e.printStackTrace();
                } finally{
                    server.accept(null, this);     //需要加上这一句,否则只会相应一次?
                    try {
                        System.out.println("server write data's length" + writeResult.get());
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    } catch (ExecutionException e) {
                        e.printStackTrace();
                    }
                }
            }
            @Override
            public void failed(Throwable exc, Object attachment) {
                System.out.println("server accept failed");
            }
        });
    }
    public static void main(String[] args) {
        new AIOServer();
        while (true) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

客户端AIOClient:

public class AIOClient {
    private AsynchronousSocketChannel channel;
    private InetSocketAddress serverAddress = new InetSocketAddress("127.0.0.1", 8088);
    private final ByteBuffer buffer = ByteBuffer.allocate(1024);
    public AIOClient() {
        try {
            channel = AsynchronousSocketChannel.open();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    private class ConnectCompletionHandler implements CompletionHandler<Void, Object> {
        AsynchronousSocketChannel channel;
        public ConnectCompletionHandler(AsynchronousSocketChannel channel) {
            this.channel = channel;
        }
        @Override
        public void completed(Void result, Object attachment) {
            System.out.println("connect server successfully");
            ByteBuffer bf = ByteBuffer.wrap("this is from client".getBytes());
            channel.write(bf, bf, new WriteCompletionHandler(channel));
            channel.read(buffer, null, new ReadCompletionHandler(channel));
        }
        @Override
        public void failed(Throwable exc, Object attachment) {
            System.out.println("connect server failed");
        }
    }

    private class WriteCompletionHandler implements CompletionHandler<Integer, ByteBuffer> {
        AsynchronousSocketChannel channel;
        public WriteCompletionHandler(AsynchronousSocketChannel channel) {
            this.channel = channel;
        }
        @Override
        public void completed(Integer result, ByteBuffer attachment) {
            if (attachment.hasRemaining()) { // 有剩余,就一致写。
                channel.write(attachment, attachment, this);
            }
            System.out.println("write successfully");
        }
        @Override
        public void failed(Throwable exc, ByteBuffer attachment) {
            System.out.println("write failed");
        }
    }

    private class ReadCompletionHandler implements CompletionHandler<Integer, Object> {
        AsynchronousSocketChannel channel;
        public ReadCompletionHandler(AsynchronousSocketChannel channel) {
            this.channel = channel;
        }
        @Override
        public void completed(Integer result, Object attachment) {
            buffer.flip();
            System.out.println("read successfully,and data is :" + buffer.array());
        }
        @Override
        public void failed(Throwable exc, Object attachment) {
            System.out.println("read failed");
        }
    }
    private void bind() {
        channel.connect(serverAddress, null, new ConnectCompletionHandler(this.channel));
    }
    public static void main(String[] args) {
        new AIOClient().bind();
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

整体思路,类似于注册,注册一个回调方法,当有socket连接时候,就会自动调用方法,需要注意以下几个点:
1. AsynchronousServerChannel的accept方法:

 public abstract <A> void accept(A attachment,CompletionHandler<AsynchronousSocketChannel,? super A> handler); 

它的CompletionHandler 第二个参数是AsynchronousSocketChannel,第一个是Object。

  1. 由于具有延迟,所以AsynchronousServerChannel的read和write方法,返回类型都是:Future<Integer> ,也就是你可以利用返回值去查询写了多少数据。
  2. 而AsynchronousSocketChannel的read和write方法,需要用CompletionHandler时,返回的结果参数都是Integer,而不是直接的传递数据结果。

猜你喜欢

转载自blog.csdn.net/anLA_/article/details/79679107